chore: ruff formatting

This commit is contained in:
neoarz
2025-11-02 23:32:52 -05:00
parent 2ce2c69a87
commit 1eff6c9f53
91 changed files with 3824 additions and 2518 deletions

View File

@@ -18,7 +18,7 @@
## Commands ## Commands
![Total Commands](https://img.shields.io/badge/Total%20Commands-70-5865F2) ![Total Commands](https://img.shields.io/badge/Total%20Commands-71-5865F2)
| Command group | Subcommands | | Command group | Subcommands |
| ------------ | --- | | ------------ | --- |

41
bot.py
View File

@@ -43,7 +43,6 @@ intents.presences = True
intents.members = True intents.members = True
logger = setup_logger() logger = setup_logger()
@@ -67,7 +66,7 @@ class DiscordBot(commands.Bot):
) as db: ) as db:
with open( with open(
f"{os.path.realpath(os.path.dirname(__file__))}/database/schema.sql", f"{os.path.realpath(os.path.dirname(__file__))}/database/schema.sql",
encoding = "utf-8" encoding="utf-8",
) as file: ) as file:
await db.executescript(file.read()) await db.executescript(file.read())
await db.commit() await db.commit()
@@ -75,11 +74,13 @@ class DiscordBot(commands.Bot):
async def load_cogs(self) -> None: async def load_cogs(self) -> None:
cogs_path = f"{os.path.realpath(os.path.dirname(__file__))}/cogs" cogs_path = f"{os.path.realpath(os.path.dirname(__file__))}/cogs"
disabled_env = os.getenv("DISABLED_COGS", "") disabled_env = os.getenv("DISABLED_COGS", "")
disabled_cogs = {entry.strip().lower() for entry in disabled_env.split(",") if entry.strip()} disabled_cogs = {
entry.strip().lower() for entry in disabled_env.split(",") if entry.strip()
}
for folder in os.listdir(cogs_path): for folder in os.listdir(cogs_path):
folder_path = os.path.join(cogs_path, folder) folder_path = os.path.join(cogs_path, folder)
if os.path.isdir(folder_path) and not folder.startswith('__'): if os.path.isdir(folder_path) and not folder.startswith("__"):
init_file = os.path.join(folder_path, "__init__.py") init_file = os.path.join(folder_path, "__init__.py")
if os.path.exists(init_file): if os.path.exists(init_file):
try: try:
@@ -93,15 +94,22 @@ class DiscordBot(commands.Bot):
) )
else: else:
for file in os.listdir(folder_path): for file in os.listdir(folder_path):
if file.endswith(".py") and not file.startswith('__'): if file.endswith(".py") and not file.startswith("__"):
extension = file[:-3] extension = file[:-3]
full_name = f"{folder}.{extension}".lower() full_name = f"{folder}.{extension}".lower()
if extension.lower() in disabled_cogs or full_name in disabled_cogs: if (
self.logger.info(f"Skipped disabled extension '{full_name}'") extension.lower() in disabled_cogs
or full_name in disabled_cogs
):
self.logger.info(
f"Skipped disabled extension '{full_name}'"
)
continue continue
try: try:
await self.load_extension(f"cogs.{folder}.{extension}") await self.load_extension(f"cogs.{folder}.{extension}")
self.logger.info(f"Loaded extension '{folder}.{extension}'") self.logger.info(
f"Loaded extension '{folder}.{extension}'"
)
except Exception as e: except Exception as e:
exception = f"{type(e).__name__}: {e}" exception = f"{type(e).__name__}: {e}"
self.logger.error( self.logger.error(
@@ -109,7 +117,7 @@ class DiscordBot(commands.Bot):
) )
for file in os.listdir(cogs_path): for file in os.listdir(cogs_path):
if file.endswith(".py") and not file.startswith('__'): if file.endswith(".py") and not file.startswith("__"):
extension = file[:-3] extension = file[:-3]
if extension.lower() in disabled_cogs: if extension.lower() in disabled_cogs:
self.logger.info(f"Skipped disabled extension '{extension}'") self.logger.info(f"Skipped disabled extension '{extension}'")
@@ -148,11 +156,12 @@ class DiscordBot(commands.Bot):
for member in app_info.team.members: for member in app_info.team.members:
self.logger.info(f"Team member: {member.name} (ID: {member.id})") self.logger.info(f"Team member: {member.name} (ID: {member.id})")
else: else:
self.logger.info(f"Bot owner: {app_info.owner.name} (ID: {app_info.owner.id})") self.logger.info(
f"Bot owner: {app_info.owner.name} (ID: {app_info.owner.id})"
)
except Exception as e: except Exception as e:
self.logger.error(f"Error fetching application info: {e}") self.logger.error(f"Error fetching application info: {e}")
await self.init_db() await self.init_db()
await self.load_cogs() await self.load_cogs()
self.status_task.start() self.status_task.start()
@@ -196,7 +205,9 @@ class DiscordBot(commands.Bot):
if self.user in message.mentions: if self.user in message.mentions:
try: try:
emoji_string = "<a:PandaPing:1417550314260926575>" emoji_string = "<a:PandaPing:1417550314260926575>"
self.logger.debug(f"Attempting to react with PandaPing emoji: {emoji_string}") self.logger.debug(
f"Attempting to react with PandaPing emoji: {emoji_string}"
)
await message.add_reaction(emoji_string) await message.add_reaction(emoji_string)
self.logger.debug("Successfully reacted with PandaPing emoji") self.logger.debug("Successfully reacted with PandaPing emoji")
except Exception as e: except Exception as e:
@@ -206,7 +217,9 @@ class DiscordBot(commands.Bot):
await message.add_reaction("👋") await message.add_reaction("👋")
self.logger.debug("Successfully reacted with wave emoji") self.logger.debug("Successfully reacted with wave emoji")
except Exception as fallback_error: except Exception as fallback_error:
self.logger.debug(f"Failed to react with fallback emoji: {fallback_error}") self.logger.debug(
f"Failed to react with fallback emoji: {fallback_error}"
)
await self.process_commands(message) await self.process_commands(message)
async def on_command_completion(self, context: Context) -> None: async def on_command_completion(self, context: Context) -> None:
@@ -287,7 +300,7 @@ class DiscordBot(commands.Bot):
bot = DiscordBot() bot = DiscordBot()
if __name__ == "__main__": if __name__ == "__main__":
os.system('clear' if os.name == 'posix' else 'cls') os.system("clear" if os.name == "posix" else "cls")
print(ascii) print(ascii)

View File

@@ -28,7 +28,10 @@ class FeedbackForm(discord.ui.Modal, title="Feedback"):
title="Thank You!", title="Thank You!",
description="Your feedback has been submitted, the owners have been notified about it.", description="Your feedback has been submitted, the owners have been notified about it.",
color=0x7289DA, color=0x7289DA,
).set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/gSxqzV.png"), ).set_author(
name="Feedback System",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
),
ephemeral=True, ephemeral=True,
) )
@@ -38,7 +41,10 @@ class FeedbackForm(discord.ui.Modal, title="Feedback"):
title="New Feedback", title="New Feedback",
description=f"{interaction.user} (<@{interaction.user.id}>) has submitted a new feedback:\n```\n{self.feedback.value}\n```", description=f"{interaction.user} (<@{interaction.user.id}>) has submitted a new feedback:\n```\n{self.feedback.value}\n```",
color=0x7289DA, color=0x7289DA,
).set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/gSxqzV.png") ).set_author(
name="Feedback System",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
)
) )
@@ -52,16 +58,18 @@ class BotInfoView(discord.ui.View):
label="GitHub", label="GitHub",
emoji=github_emoji, emoji=github_emoji,
url="https://github.com/neoarz/syntrel", url="https://github.com/neoarz/syntrel",
style=discord.ButtonStyle.link style=discord.ButtonStyle.link,
) )
self.add_item(github_button) self.add_item(github_button)
feedback_emoji = discord.PartialEmoji(name="ThumbsUpBlueEmoji", id=1426066711500554302) feedback_emoji = discord.PartialEmoji(
name="ThumbsUpBlueEmoji", id=1426066711500554302
)
feedback_button = discord.ui.Button( feedback_button = discord.ui.Button(
label="Feedback", label="Feedback",
emoji=feedback_emoji, emoji=feedback_emoji,
style=discord.ButtonStyle.secondary, style=discord.ButtonStyle.secondary,
custom_id="feedback_button" custom_id="feedback_button",
) )
feedback_button.callback = self.feedback_callback feedback_button.callback = self.feedback_callback
self.add_item(feedback_button) self.add_item(feedback_button)
@@ -71,7 +79,7 @@ class BotInfoView(discord.ui.View):
label="Bug Report", label="Bug Report",
emoji=bug_emoji, emoji=bug_emoji,
url="https://github.com/neoarz/Syntrel/issues", url="https://github.com/neoarz/Syntrel/issues",
style=discord.ButtonStyle.link style=discord.ButtonStyle.link,
) )
self.add_item(bug_button) self.add_item(bug_button)
@@ -87,16 +95,20 @@ class BotInfo(commands.Cog, name="botinfo"):
@commands.Cog.listener() @commands.Cog.listener()
async def on_guild_join(self, guild): async def on_guild_join(self, guild):
channel = guild.system_channel or next( channel = guild.system_channel or next(
(c for c in guild.text_channels if c.permissions_for(guild.me).send_messages), (
None c
for c in guild.text_channels
if c.permissions_for(guild.me).send_messages
),
None,
) )
if channel: if channel:
ny_tz = pytz.timezone('America/New_York') ny_tz = pytz.timezone("America/New_York")
current_time = datetime.now(ny_tz).strftime("%m/%d/%y, %I:%M %p") current_time = datetime.now(ny_tz).strftime("%m/%d/%y, %I:%M %p")
description_text = ( description_text = (
"Heyooo! I'm Syntrel, a bot made to help with [SideStore](https://discord.gg/3DwCwpBHfv), [MeloNX](https://discord.gg/Q4VkbkYfmk), and [idevice](https://discord.gg/ZnNcrRT3M8). I even have some cool extras! If you encounter any issues, please file a bug report. If you have any feedback or suggestions, simply select \"Feedback\"! <:HeardPanda:1417619745896660992>\n\n" 'Heyooo! I\'m Syntrel, a bot made to help with [SideStore](https://discord.gg/3DwCwpBHfv), [MeloNX](https://discord.gg/Q4VkbkYfmk), and [idevice](https://discord.gg/ZnNcrRT3M8). I even have some cool extras! If you encounter any issues, please file a bug report. If you have any feedback or suggestions, simply select "Feedback"! <:HeardPanda:1417619745896660992>\n\n'
"**New to Syntrel?** Run `/help` to get started and explore all available commands!\n\n" "**New to Syntrel?** Run `/help` to get started and explore all available commands!\n\n"
f"**Owner:** [neoarz](https://discordapp.com/users/1015372540937502851)\n" f"**Owner:** [neoarz](https://discordapp.com/users/1015372540937502851)\n"
f"**Python Version:** {platform.python_version()}\n" f"**Python Version:** {platform.python_version()}\n"
@@ -109,9 +121,17 @@ class BotInfo(commands.Cog, name="botinfo"):
description=description_text, description=description_text,
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Syntrel", icon_url="https://github.com/neoarz/Syntrel/blob/main/assets/icon.png?raw=true") embed.set_author(
embed.set_image(url="https://github.com/neoarz/Syntrel/raw/main/assets/bannerdark.png") name="Syntrel",
embed.set_footer(text=f"neoarz • {current_time}", icon_url="https://yes.nighty.works/raw/P1Us35.webp") icon_url="https://github.com/neoarz/Syntrel/blob/main/assets/icon.png?raw=true",
)
embed.set_image(
url="https://github.com/neoarz/Syntrel/raw/main/assets/bannerdark.png"
)
embed.set_footer(
text=f"neoarz • {current_time}",
icon_url="https://yes.nighty.works/raw/P1Us35.webp",
)
view = BotInfoView(self.bot) view = BotInfoView(self.bot)
@@ -129,11 +149,11 @@ class BotInfo(commands.Cog, name="botinfo"):
if context.interaction: if context.interaction:
await context.interaction.response.defer(ephemeral=False) await context.interaction.response.defer(ephemeral=False)
ny_tz = pytz.timezone('America/New_York') ny_tz = pytz.timezone("America/New_York")
current_time = datetime.now(ny_tz).strftime("%m/%d/%y, %I:%M %p") current_time = datetime.now(ny_tz).strftime("%m/%d/%y, %I:%M %p")
description_text = ( description_text = (
"Heyooo! I'm Syntrel, a bot made to help with [SideStore](https://discord.gg/3DwCwpBHfv), [MeloNX](https://discord.gg/Q4VkbkYfmk), and [idevice](https://discord.gg/ZnNcrRT3M8). I even have some cool extras! If you encounter any issues, please file a bug report. If you have any feedback or suggestions, simply select \"Feedback\"! <:HeardPanda:1417619745896660992>\n\n" 'Heyooo! I\'m Syntrel, a bot made to help with [SideStore](https://discord.gg/3DwCwpBHfv), [MeloNX](https://discord.gg/Q4VkbkYfmk), and [idevice](https://discord.gg/ZnNcrRT3M8). I even have some cool extras! If you encounter any issues, please file a bug report. If you have any feedback or suggestions, simply select "Feedback"! <:HeardPanda:1417619745896660992>\n\n'
"**New to Syntrel?** Run `/help` to get started and explore all available commands!\n\n" "**New to Syntrel?** Run `/help` to get started and explore all available commands!\n\n"
f"**Owner:** [neoarz](https://discordapp.com/users/1015372540937502851)\n" f"**Owner:** [neoarz](https://discordapp.com/users/1015372540937502851)\n"
f"**Python Version:** {platform.python_version()}\n" f"**Python Version:** {platform.python_version()}\n"
@@ -146,9 +166,17 @@ class BotInfo(commands.Cog, name="botinfo"):
description=description_text, description=description_text,
color=0x7289DA, color=0x7289DA,
) )
embed1.set_author(name="Syntrel", icon_url="https://github.com/neoarz/Syntrel/blob/main/assets/icon.png?raw=true") embed1.set_author(
embed1.set_image(url="https://github.com/neoarz/Syntrel/raw/main/assets/bannerdark.png") name="Syntrel",
embed1.set_footer(text=f"neoarz • {current_time}", icon_url="https://yes.nighty.works/raw/P1Us35.webp") icon_url="https://github.com/neoarz/Syntrel/blob/main/assets/icon.png?raw=true",
)
embed1.set_image(
url="https://github.com/neoarz/Syntrel/raw/main/assets/bannerdark.png"
)
embed1.set_footer(
text=f"neoarz • {current_time}",
icon_url="https://yes.nighty.works/raw/P1Us35.webp",
)
embed2 = discord.Embed( embed2 = discord.Embed(
title="Contributors", title="Contributors",
@@ -165,12 +193,16 @@ class BotInfo(commands.Cog, name="botinfo"):
embed2.set_image(url="attachment://contributors.png") embed2.set_image(url="attachment://contributors.png")
if context.interaction: if context.interaction:
await context.interaction.followup.send(embeds=[embed1, embed2], file=file, view=view) await context.interaction.followup.send(
embeds=[embed1, embed2], file=file, view=view
)
else: else:
await context.send(embeds=[embed1, embed2], file=file, view=view) await context.send(embeds=[embed1, embed2], file=file, view=view)
else: else:
if context.interaction: if context.interaction:
await context.interaction.followup.send(embeds=[embed1, embed2], view=view) await context.interaction.followup.send(
embeds=[embed1, embed2], view=view
)
else: else:
await context.send(embeds=[embed1, embed2], view=view) await context.send(embeds=[embed1, embed2], view=view)

View File

@@ -29,9 +29,11 @@ class Events(commands.GroupCog, name="events"):
embed = discord.Embed( embed = discord.Embed(
title="Events Commands", title="Events Commands",
description="Use `.events <subcommand>` or `/events <subcommand>`.", description="Use `.events <subcommand>` or `/events <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Events", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
embed.add_field(name="Available", value="baitbot", inline=False) embed.add_field(name="Available", value="baitbot", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
@@ -50,8 +52,7 @@ class Events(commands.GroupCog, name="events"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@has_protected_role() @has_protected_role()
@commands.hybrid_command( @commands.hybrid_command(
name="baitbot", name="baitbot", description="View bait bot configuration and status."
description="View bait bot configuration and status."
) )
async def baitbot(self, context): async def baitbot(self, context):
return await baitbot_command()(self, context) return await baitbot_command()(self, context)

View File

@@ -42,29 +42,38 @@ BAIT_CONFIGS = {
}, },
} }
BAN_REASON = 'Detected bot/scammer in bait channel' BAN_REASON = "Detected bot/scammer in bait channel"
def has_protected_role(): def has_protected_role():
async def predicate(context: Context): async def predicate(context: Context):
if not context.guild: if not context.guild:
context.bot.logger.warning(f'[BAITBOT] Unauthorized baitbot command attempt by {context.author} ({context.author.id}) in DMs') context.bot.logger.warning(
f"[BAITBOT] Unauthorized baitbot command attempt by {context.author} ({context.author.id}) in DMs"
)
embed = discord.Embed( embed = discord.Embed(
title="Permission Denied", title="Permission Denied",
description="You don't have permission to use this command.", description="You don't have permission to use this command.",
color=0xE02B2B color=0xE02B2B,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
) )
embed.set_author(name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png")
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return False return False
if not hasattr(context.author, 'roles'): if not hasattr(context.author, "roles"):
context.bot.logger.warning(f'[BAITBOT] Unauthorized baitbot command attempt by {context.author} ({context.author.id}) in {context.guild.name} - no roles') context.bot.logger.warning(
f"[BAITBOT] Unauthorized baitbot command attempt by {context.author} ({context.author.id}) in {context.guild.name} - no roles"
)
embed = discord.Embed( embed = discord.Embed(
title="Permission Denied", title="Permission Denied",
description="You don't have permission to use this command.", description="You don't have permission to use this command.",
color=0xE02B2B color=0xE02B2B,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
) )
embed.set_author(name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png")
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return False return False
@@ -74,28 +83,39 @@ def has_protected_role():
protected_role = context.guild.get_role(protected_role_id) protected_role = context.guild.get_role(protected_role_id)
if protected_role: if protected_role:
for role in context.author.roles: for role in context.author.roles:
if role.position >= protected_role.position and role.id != context.guild.default_role.id: if (
role.position >= protected_role.position
and role.id != context.guild.default_role.id
):
return True return True
context.bot.logger.warning(f'[BAITBOT] Unauthorized baitbot command attempt by {context.author} ({context.author.id}) in {context.guild.name} - insufficient role permissions') context.bot.logger.warning(
f"[BAITBOT] Unauthorized baitbot command attempt by {context.author} ({context.author.id}) in {context.guild.name} - insufficient role permissions"
)
embed = discord.Embed( embed = discord.Embed(
title="Permission Denied", title="Permission Denied",
description="You don't have permission to use this command.", description="You don't have permission to use this command.",
color=0xE02B2B color=0xE02B2B,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
) )
embed.set_author(name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png")
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return False return False
return commands.check(predicate) return commands.check(predicate)
def baitbot_command(): def baitbot_command():
async def wrapper(self, context: Context): async def wrapper(self, context: Context):
embed = discord.Embed( embed = discord.Embed(
title="Bait Bot", title="Bait Bot",
description="Bans people who post in a specific channel.", description="Bans people who post in a specific channel.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
) )
embed.set_author(name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png")
found_config = False found_config = False
if BAIT_CONFIGS: if BAIT_CONFIGS:
@@ -112,24 +132,36 @@ def baitbot_command():
channel_displays = [] channel_displays = []
for channel_id in channel_ids: for channel_id in channel_ids:
channel = context.guild.get_channel(channel_id) channel = context.guild.get_channel(channel_id)
channel_display = f"<#{channel_id}> (`{channel_id}`)" if channel else f"`{channel_id}`" channel_display = (
f"<#{channel_id}> (`{channel_id}`)"
if channel
else f"`{channel_id}`"
)
channel_displays.append(channel_display) channel_displays.append(channel_display)
channels_text = "\n".join(channel_displays) if channel_displays else "Not set" channels_text = (
"\n".join(channel_displays) if channel_displays else "Not set"
)
role = context.guild.get_role(role_id) role = context.guild.get_role(role_id)
role_display = f"<@&{role_id}> (`{role_id}`)" if role else f"`{role_id}`" role_display = (
f"<@&{role_id}> (`{role_id}`)" if role else f"`{role_id}`"
)
log_channel_id = config.get("log_channel_id") log_channel_id = config.get("log_channel_id")
log_channel = None log_channel = None
if log_channel_id: if log_channel_id:
log_channel = context.guild.get_channel(log_channel_id) log_channel = context.guild.get_channel(log_channel_id)
log_display = f"<#{log_channel_id}> (`{log_channel_id}`)" if log_channel else (f"`{log_channel_id}`" if log_channel_id else "Not set") log_display = (
f"<#{log_channel_id}> (`{log_channel_id}`)"
if log_channel
else (f"`{log_channel_id}`" if log_channel_id else "Not set")
)
embed.add_field( embed.add_field(
name="\u200b", name="\u200b",
value=f"Channels:\n{channels_text}\n\nProtected Role:\n{role_display}\n\nLog Channel:\n{log_display}", value=f"Channels:\n{channels_text}\n\nProtected Role:\n{role_display}\n\nLog Channel:\n{log_display}",
inline=False inline=False,
) )
found_config = True found_config = True
@@ -137,15 +169,17 @@ def baitbot_command():
embed.add_field( embed.add_field(
name="No Configurations", name="No Configurations",
value="No bait channels configured for this server", value="No bait channels configured for this server",
inline=False inline=False,
) )
if context.guild and context.guild.icon: if context.guild and context.guild.icon:
embed.set_thumbnail(url=context.guild.icon.url) embed.set_thumbnail(url=context.guild.icon.url)
await context.send(embed=embed) await context.send(embed=embed)
return wrapper return wrapper
class BaitBotListener(commands.Cog): class BaitBotListener(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@@ -180,12 +214,17 @@ class BaitBotListener(commands.Cog):
protected_role_id = bait_config.get("protected_role_id") protected_role_id = bait_config.get("protected_role_id")
is_protected = False is_protected = False
if protected_role_id and hasattr(message.author, 'roles'): if protected_role_id and hasattr(message.author, "roles"):
protected_role = message.guild.get_role(protected_role_id) protected_role = message.guild.get_role(protected_role_id)
if protected_role: if protected_role:
for role in message.author.roles: for role in message.author.roles:
if role.position >= protected_role.position and role.id != message.guild.default_role.id: if (
self.bot.logger.info(f'[BAITBOT] Skipped banning {message.author} ({message.author.id}) in #{message.channel.name}: protected role ({role.name})') role.position >= protected_role.position
and role.id != message.guild.default_role.id
):
self.bot.logger.info(
f"[BAITBOT] Skipped banning {message.author} ({message.author.id}) in #{message.channel.name}: protected role ({role.name})"
)
is_protected = True is_protected = True
break break
@@ -195,51 +234,86 @@ class BaitBotListener(commands.Cog):
try: try:
await message.delete() await message.delete()
self.bot.logger.info(f'[BAITBOT] Deleted message from {message.author} in #{message.channel.name}') self.bot.logger.info(
f"[BAITBOT] Deleted message from {message.author} in #{message.channel.name}"
)
except Exception as e: except Exception as e:
self.bot.logger.warning(f'[BAITBOT] Could not delete message from {message.author}: {e}') self.bot.logger.warning(
f"[BAITBOT] Could not delete message from {message.author}: {e}"
)
banned = False banned = False
if not is_protected: if not is_protected:
try: try:
self.bot.logger.warning(f'[BAITBOT] Detected user in bait channel [{config_name}]: {message.author.name} ({message.author.id}) in #{message.channel.name}') self.bot.logger.warning(
f"[BAITBOT] Detected user in bait channel [{config_name}]: {message.author.name} ({message.author.id}) in #{message.channel.name}"
)
if not message.guild.me.guild_permissions.ban_members: if not message.guild.me.guild_permissions.ban_members:
self.bot.logger.error(f'[BAITBOT] No permission to ban members in {message.guild.name}') self.bot.logger.error(
f"[BAITBOT] No permission to ban members in {message.guild.name}"
)
else: else:
try: try:
await message.author.ban(reason=BAN_REASON, delete_message_days=7) await message.author.ban(
self.bot.logger.info(f'[BAITBOT] Banned {message.author.name} - deleted messages from last 7 days') reason=BAN_REASON, delete_message_days=7
)
self.bot.logger.info(
f"[BAITBOT] Banned {message.author.name} - deleted messages from last 7 days"
)
banned = True banned = True
except discord.Forbidden: except discord.Forbidden:
self.bot.logger.error(f'[BAITBOT] Could not ban {message.author.name}: missing permissions') self.bot.logger.error(
f"[BAITBOT] Could not ban {message.author.name}: missing permissions"
)
except Exception as e: except Exception as e:
self.bot.logger.error(f'[BAITBOT] Error banning {message.author.name}: {e}') self.bot.logger.error(
f"[BAITBOT] Error banning {message.author.name}: {e}"
)
if banned: if banned:
await asyncio.sleep(2) await asyncio.sleep(2)
try: try:
await message.guild.unban(message.author, reason="Auto-unban after cleanup") await message.guild.unban(
self.bot.logger.info(f'[BAITBOT] Unbanned {message.author.name} - cleanup complete') message.author, reason="Auto-unban after cleanup"
)
self.bot.logger.info(
f"[BAITBOT] Unbanned {message.author.name} - cleanup complete"
)
except Exception as e: except Exception as e:
self.bot.logger.error(f'[BAITBOT] Error unbanning {message.author.name}: {e}') self.bot.logger.error(
f"[BAITBOT] Error unbanning {message.author.name}: {e}"
)
except Exception as e: except Exception as e:
self.bot.logger.error(f'[BAITBOT] Error handling bait message: {e}') self.bot.logger.error(f"[BAITBOT] Error handling bait message: {e}")
log_channel_id = bait_config.get("log_channel_id") log_channel_id = bait_config.get("log_channel_id")
if log_channel_id: if log_channel_id:
try: try:
log_channel = self.bot.get_channel(log_channel_id) log_channel = self.bot.get_channel(log_channel_id)
if log_channel: if log_channel:
action_text = "Message deleted (user banned and unbanned)" if banned else "Message deleted (protected user)" if is_protected else "Message deleted" action_text = (
"Message deleted (user banned and unbanned)"
if banned
else "Message deleted (protected user)"
if is_protected
else "Message deleted"
)
log_embed = discord.Embed( log_embed = discord.Embed(
title="Bait Bot", title="Bait Bot",
description=action_text, description=action_text,
color=0xE02B2B, color=0xE02B2B,
timestamp=message.created_at timestamp=message.created_at,
)
log_embed.set_author(
name=str(message.author),
icon_url=message.author.display_avatar.url,
)
log_embed.add_field(
name="User", value=message.author.mention, inline=True
)
log_embed.add_field(
name="Channel", value=message.channel.mention, inline=True
) )
log_embed.set_author(name=str(message.author), icon_url=message.author.display_avatar.url)
log_embed.add_field(name="User", value=message.author.mention, inline=True)
log_embed.add_field(name="Channel", value=message.channel.mention, inline=True)
combined_content = [] combined_content = []
if message_content and message_content != "*No text content*": if message_content and message_content != "*No text content*":
@@ -248,16 +322,25 @@ class BaitBotListener(commands.Cog):
image_url = None image_url = None
if message_attachments: if message_attachments:
for attachment in message_attachments: for attachment in message_attachments:
if attachment.content_type and attachment.content_type.startswith("image/"): if (
attachment.content_type
and attachment.content_type.startswith("image/")
):
if not image_url: if not image_url:
image_url = attachment.url image_url = attachment.url
combined_content.append(attachment.filename) combined_content.append(attachment.filename)
content_text = "\n".join(combined_content) if combined_content else "*No content*" content_text = (
"\n".join(combined_content)
if combined_content
else "*No content*"
)
if len(content_text) > 1000: if len(content_text) > 1000:
content_text = content_text[:997] + "..." content_text = content_text[:997] + "..."
log_embed.add_field(name="Content", value=f"```\n{content_text}\n```", inline=False) log_embed.add_field(
name="Content", value=f"```\n{content_text}\n```", inline=False
)
if image_url: if image_url:
log_embed.set_image(url=image_url) log_embed.set_image(url=image_url)
@@ -267,24 +350,38 @@ class BaitBotListener(commands.Cog):
for embed in message_embeds[:3]: for embed in message_embeds[:3]:
embed_desc = f"**Embed:** {embed.title or 'Untitled'}\n" embed_desc = f"**Embed:** {embed.title or 'Untitled'}\n"
if embed.description: if embed.description:
desc_text = embed.description[:200] + "..." if len(embed.description) > 200 else embed.description desc_text = (
embed.description[:200] + "..."
if len(embed.description) > 200
else embed.description
)
embed_desc += f"{desc_text}\n" embed_desc += f"{desc_text}\n"
if embed.url: if embed.url:
embed_desc += f"[Link]({embed.url})" embed_desc += f"[Link]({embed.url})"
embed_info.append(embed_desc) embed_info.append(embed_desc)
if embed_info: if embed_info:
log_embed.add_field(name="Embeds", value="\n\n".join(embed_info), inline=False) log_embed.add_field(
name="Embeds",
value="\n\n".join(embed_info),
inline=False,
)
log_embed.set_footer(text=f"Message ID: {message.id}") log_embed.set_footer(text=f"Message ID: {message.id}")
try: try:
await log_channel.send(embed=log_embed) await log_channel.send(embed=log_embed)
self.bot.logger.info(f'[BAITBOT] Sent log to #{log_channel.name}') self.bot.logger.info(
f"[BAITBOT] Sent log to #{log_channel.name}"
)
except discord.Forbidden: except discord.Forbidden:
self.bot.logger.error(f'[BAITBOT] No permission to send log to #{log_channel.name}') self.bot.logger.error(
f"[BAITBOT] No permission to send log to #{log_channel.name}"
)
except Exception as e: except Exception as e:
self.bot.logger.error(f'[BAITBOT] Error sending log: {e}') self.bot.logger.error(f"[BAITBOT] Error sending log: {e}")
else: else:
self.bot.logger.warning(f'[BAITBOT] Log channel {log_channel_id} not found') self.bot.logger.warning(
f"[BAITBOT] Log channel {log_channel_id} not found"
)
except Exception as e: except Exception as e:
self.bot.logger.error(f'[BAITBOT] Error handling log channel: {e}') self.bot.logger.error(f"[BAITBOT] Error handling log channel: {e}")

View File

@@ -22,10 +22,16 @@ class Fun(commands.GroupCog, name="fun"):
embed = discord.Embed( embed = discord.Embed(
title="Fun Commands", title="Fun Commands",
description="Use `.fun <subcommand>` or slash `/fun <subcommand>`.", description="Use `.fun <subcommand>` or slash `/fun <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
)
embed.add_field(
name="Available",
value="coinflip, 8ball, minesweeper, randomfact, rps",
inline=False,
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
embed.add_field(name="Available", value="coinflip, 8ball, minesweeper, randomfact, rps", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
@@ -67,8 +73,7 @@ class Fun(commands.GroupCog, name="fun"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="coinflip", name="coinflip", description="Make a coin flip, but give your bet before."
description="Make a coin flip, but give your bet before."
) )
async def coinflip(self, context): async def coinflip(self, context):
return await coinflip_command()(self, context) return await coinflip_command()(self, context)
@@ -83,8 +88,7 @@ class Fun(commands.GroupCog, name="fun"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="minesweeper", name="minesweeper", description="Play a buttoned minesweeper mini-game."
description="Play a buttoned minesweeper mini-game."
) )
async def minesweeper(self, context): async def minesweeper(self, context):
return await minesweeper_command()(self, context) return await minesweeper_command()(self, context)
@@ -101,6 +105,7 @@ class Fun(commands.GroupCog, name="fun"):
async def rock_paper_scissors(self, context): async def rock_paper_scissors(self, context):
return await rps_command()(self, context) return await rps_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Fun(bot) cog = Fun(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -2,6 +2,7 @@ import random
import discord import discord
from discord.ext import commands from discord.ext import commands
class Choice(discord.ui.View): class Choice(discord.ui.View):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
@@ -21,19 +22,19 @@ class Choice(discord.ui.View):
self.value = "tails" self.value = "tails"
self.stop() self.stop()
def coinflip_command(): def coinflip_command():
@commands.hybrid_command( @commands.hybrid_command(
name="coinflip", name="coinflip", description="Make a coin flip, but give your bet before."
description="Make a coin flip, but give your bet before."
) )
async def coinflip(self, context): async def coinflip(self, context):
buttons = Choice() buttons = Choice()
embed = discord.Embed( embed = discord.Embed(
title="Coinflip", title="Coinflip", description="What is your bet?", color=0x7289DA
description="What is your bet?", )
color=0x7289DA embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
message = await context.send(embed=embed, view=buttons) message = await context.send(embed=embed, view=buttons)
await buttons.wait() await buttons.wait()
result = random.choice(["heads", "tails"]) result = random.choice(["heads", "tails"])
@@ -43,14 +44,18 @@ def coinflip_command():
description=f"Correct! You guessed `{buttons.value}` and I flipped the coin to `{result}`.", description=f"Correct! You guessed `{buttons.value}` and I flipped the coin to `{result}`.",
color=0x00FF00, color=0x00FF00,
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
)
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Coinflip", title="Coinflip",
description=f"Woops! You guessed `{buttons.value}` and I flipped the coin to `{result}`, better luck next time!", description=f"Woops! You guessed `{buttons.value}` and I flipped the coin to `{result}`, better luck next time!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
)
await message.edit(embed=embed, view=None, content=None) await message.edit(embed=embed, view=None, content=None)
return coinflip return coinflip

View File

@@ -2,6 +2,7 @@ import random
import discord import discord
from discord.ext import commands from discord.ext import commands
def eightball_command(): def eightball_command():
@commands.hybrid_command( @commands.hybrid_command(
name="8ball", name="8ball",
@@ -35,7 +36,9 @@ def eightball_command():
description=f"{random.choice(answers)}", description=f"{random.choice(answers)}",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
)
embed.set_footer(text=f"The question was: {question}") embed.set_footer(text=f"The question was: {question}")
await context.send(embed=embed) await context.send(embed=embed)

View File

@@ -5,9 +5,12 @@ from discord.ext import commands
import asyncio import asyncio
import time import time
class RowButton(discord.ui.Button): class RowButton(discord.ui.Button):
def __init__(self, ctx, label, custom_id, bombs, board): def __init__(self, ctx, label, custom_id, bombs, board):
super().__init__(label=label, style=discord.ButtonStyle.grey, custom_id=custom_id) super().__init__(
label=label, style=discord.ButtonStyle.grey, custom_id=custom_id
)
self.ctx = ctx self.ctx = ctx
self.bombs = bombs self.bombs = bombs
self.board = board self.board = board
@@ -19,7 +22,9 @@ class RowButton(discord.ui.Button):
current_time = time.time() current_time = time.time()
if current_time - view.last_interaction < 0.5: if current_time - view.last_interaction < 0.5:
try: try:
return await interaction.response.send_message("Please wait before clicking again.", ephemeral=True) return await interaction.response.send_message(
"Please wait before clicking again.", ephemeral=True
)
except: except:
return return
@@ -40,7 +45,9 @@ class RowButton(discord.ui.Button):
b_id = self.custom_id b_id = self.custom_id
if int(b_id[5:]) in view.moves: if int(b_id[5:]) in view.moves:
return await interaction.followup.send("That part is already taken.", ephemeral=True) return await interaction.followup.send(
"That part is already taken.", ephemeral=True
)
if not view.bombs_generated: if not view.bombs_generated:
view.generate_bombs(int(b_id[5:])) view.generate_bombs(int(b_id[5:]))
@@ -74,13 +81,13 @@ class RowButton(discord.ui.Button):
return count return count
count = checkpos(count, rawpos, pos) count = checkpos(count, rawpos, pos)
number = 8-len(count) number = 8 - len(count)
self.label = str(number) if number > 0 else "0" self.label = str(number) if number > 0 else "0"
self.style = discord.ButtonStyle.green self.style = discord.ButtonStyle.green
pos = int(b_id[5:]) pos = int(b_id[5:])
view.board[view.GetBoardRow(pos)][ view.board[view.GetBoardRow(pos)][view.GetBoardPos(pos)] = (
view.GetBoardPos(pos) str(number) if number > 0 else "0"
] = str(number) if number > 0 else "0" )
view.moves.append(pos) view.moves.append(pos)
if len(view.moves) + len(self.bombs) == 25: if len(view.moves) + len(self.bombs) == 25:
await view.EndGame() await view.EndGame()
@@ -93,6 +100,7 @@ class RowButton(discord.ui.Button):
else: else:
raise raise
class MsView(discord.ui.View): class MsView(discord.ui.View):
def __init__(self, ctx, options, bomb_count, board): def __init__(self, ctx, options, bomb_count, board):
super().__init__(timeout=300) super().__init__(timeout=300)
@@ -114,13 +122,15 @@ class MsView(discord.ui.View):
while len(bombpositions) < self.bomb_count: while len(bombpositions) < self.bomb_count:
random_index = random.randint(0, 24) random_index = random.randint(0, 24)
if random_index not in bombpositions and random_index not in excluded_positions: if (
random_index not in bombpositions
and random_index not in excluded_positions
):
bombpositions.append(random_index) bombpositions.append(random_index)
self.bombs = bombpositions self.bombs = bombpositions
self.bombs_generated = True self.bombs_generated = True
for button in self.children: for button in self.children:
if isinstance(button, RowButton): if isinstance(button, RowButton):
button.bombs = self.bombs button.bombs = self.bombs
@@ -129,11 +139,11 @@ class MsView(discord.ui.View):
for button in self.children: for button in self.children:
button.disabled = True button.disabled = True
embed = discord.Embed( embed = discord.Embed(
title="Minesweeper", title="Minesweeper", description="Game timed out!", color=0xFF0000
description="Game timed out!", )
color=0xFF0000 embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
try: try:
await self.message.edit(embed=embed, view=self) await self.message.edit(embed=embed, view=self)
except: except:
@@ -149,11 +159,11 @@ class MsView(discord.ui.View):
self.board[self.GetBoardRow(pos)][self.GetBoardPos(pos)] = "💣" self.board[self.GetBoardRow(pos)][self.GetBoardPos(pos)] = "💣"
embed = discord.Embed( embed = discord.Embed(
title="Minesweeper", title="Minesweeper", description="Game Ended. You won!", color=0x00FF00
description="Game Ended. You won!", )
color=0x00FF00 embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
try: try:
await self.message.edit(embed=embed, view=self) await self.message.edit(embed=embed, view=self)
@@ -214,16 +224,16 @@ class MsView(discord.ui.View):
button.label = bombemo button.label = bombemo
button.style = discord.ButtonStyle.red button.style = discord.ButtonStyle.red
pos = int(button.custom_id[5:]) pos = int(button.custom_id[5:])
self.board[self.GetBoardRow(pos)][ self.board[self.GetBoardRow(pos)][self.GetBoardPos(pos)] = bombemo
self.GetBoardPos(pos)
] = bombemo
embed = discord.Embed( embed = discord.Embed(
title="Minesweeper", title="Minesweeper",
description=f"💥 BOOM! You hit a bomb. Game Over!\n-# gg {self.ctx.author.mention}", description=f"💥 BOOM! You hit a bomb. Game Over!\n-# gg {self.ctx.author.mention}",
color=0xE02B2B color=0xE02B2B,
)
embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
try: try:
await self.message.edit(embed=embed, view=self) await self.message.edit(embed=embed, view=self)
@@ -234,10 +244,10 @@ class MsView(discord.ui.View):
raise raise
self.stop() self.stop()
def minesweeper_command(): def minesweeper_command():
@commands.hybrid_command( @commands.hybrid_command(
name="minesweeper", name="minesweeper", description="Play a buttoned minesweeper mini-game."
description="Play a buttoned minesweeper mini-game."
) )
async def minesweeper(self, context): async def minesweeper(self, context):
board = [[" "] * 5 for _ in range(5)] board = [[" "] * 5 for _ in range(5)]
@@ -253,9 +263,11 @@ def minesweeper_command():
embed = discord.Embed( embed = discord.Embed(
title="Minesweeper", title="Minesweeper",
description=f"💣 Total Bombs: `{bomb_count}`\n\nClick the buttons to reveal the grid. Avoid the bombs!", description=f"💣 Total Bombs: `{bomb_count}`\n\nClick the buttons to reveal the grid. Avoid the bombs!",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
view = MsView(context, ExtractBlocks(), bomb_count, board) view = MsView(context, ExtractBlocks(), bomb_count, board)
message = await context.send(embed=embed, view=view) message = await context.send(embed=embed, view=view)

View File

@@ -2,6 +2,7 @@ import aiohttp
import discord import discord
from discord.ext import commands from discord.ext import commands
def randomfact_command(): def randomfact_command():
@commands.hybrid_command(name="randomfact", description="Get a random fact.") @commands.hybrid_command(name="randomfact", description="Get a random fact.")
async def randomfact(self, context): async def randomfact(self, context):
@@ -10,7 +11,9 @@ def randomfact_command():
description="This command is currently disabled.", description="This command is currently disabled.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
)
await context.send(embed=embed) await context.send(embed=embed)
return randomfact return randomfact

View File

@@ -2,6 +2,7 @@ import random
import discord import discord
from discord.ext import commands from discord.ext import commands
class RockPaperScissors(discord.ui.Select): class RockPaperScissors(discord.ui.Select):
def __init__(self) -> None: def __init__(self) -> None:
options = [ options = [
@@ -34,7 +35,9 @@ class RockPaperScissors(discord.ui.Select):
bot_choice_index = choices[bot_choice] bot_choice_index = choices[bot_choice]
result_embed = discord.Embed(title="Rock Paper Scissors", color=0x7289DA) result_embed = discord.Embed(title="Rock Paper Scissors", color=0x7289DA)
result_embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp") result_embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
)
winner = (3 + user_choice_index - bot_choice_index) % 3 winner = (3 + user_choice_index - bot_choice_index) % 3
@@ -54,11 +57,13 @@ class RockPaperScissors(discord.ui.Select):
embed=result_embed, content=None, view=None embed=result_embed, content=None, view=None
) )
class RockPaperScissorsView(discord.ui.View): class RockPaperScissorsView(discord.ui.View):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.add_item(RockPaperScissors()) self.add_item(RockPaperScissors())
def rps_command(): def rps_command():
@commands.hybrid_command( @commands.hybrid_command(
name="rps", description="Play the rock paper scissors game against the bot." name="rps", description="Play the rock paper scissors game against the bot."
@@ -68,9 +73,11 @@ def rps_command():
embed = discord.Embed( embed = discord.Embed(
title="Rock Paper Scissors", title="Rock Paper Scissors",
description="Please make your choice", description="Please make your choice",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.set_author(name="Fun", icon_url="https://yes.nighty.works/raw/eW5lLm.webp")
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return rock_paper_scissors return rock_paper_scissors

View File

@@ -33,10 +33,16 @@ class General(commands.GroupCog, name="general"):
embed = discord.Embed( embed = discord.Embed(
title="General Commands", title="General Commands",
description="Use `.general <subcommand>` or `/general <subcommand>`.", description="Use `.general <subcommand>` or `/general <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="General", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
embed.add_field(
name="Available",
value="ping, uptime, serverinfo, userinfo, feedback",
inline=False,
) )
embed.set_author(name="General", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
embed.add_field(name="Available", value="ping, uptime, serverinfo, userinfo, feedback", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
@@ -59,7 +65,9 @@ class General(commands.GroupCog, name="general"):
await self._invoke_hybrid(context, "serverinfo") await self._invoke_hybrid(context, "serverinfo")
@general_group.command(name="userinfo") @general_group.command(name="userinfo")
async def general_group_userinfo(self, context: Context, user: discord.User = None, user_id: str = None): async def general_group_userinfo(
self, context: Context, user: discord.User = None, user_id: str = None
):
await self._invoke_hybrid(context, "userinfo", user=user, user_id=user_id) await self._invoke_hybrid(context, "userinfo", user=user, user_id=user_id)
@general_group.command(name="feedback") @general_group.command(name="feedback")
@@ -96,20 +104,19 @@ class General(commands.GroupCog, name="general"):
description="Get information on a user.", description="Get information on a user.",
) )
@app_commands.describe( @app_commands.describe(
user="User to get info for", user="User to get info for", user_id="User ID to get info for"
user_id="User ID to get info for"
) )
async def userinfo(self, context, user: discord.User = None, user_id: str = None): async def userinfo(self, context, user: discord.User = None, user_id: str = None):
return await userinfo_command()(self, context, user=user, user_id=user_id) return await userinfo_command()(self, context, user=user, user_id=user_id)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="feedback", name="feedback", description="Submit a feedback for the owners of the bot"
description="Submit a feedback for the owners of the bot"
) )
async def feedback(self, context): async def feedback(self, context):
return await feedback_command()(self, context) return await feedback_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = General(bot) cog = General(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -2,6 +2,7 @@ import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
class FeedbackForm(discord.ui.Modal, title="Feeedback"): class FeedbackForm(discord.ui.Modal, title="Feeedback"):
feedback = discord.ui.TextInput( feedback = discord.ui.TextInput(
label="What do you think about this bot?", label="What do you think about this bot?",
@@ -16,10 +17,10 @@ class FeedbackForm(discord.ui.Modal, title="Feeedback"):
self.answer = str(self.feedback) self.answer = str(self.feedback)
self.stop() self.stop()
def feedback_command(): def feedback_command():
@commands.hybrid_command( @commands.hybrid_command(
name="feedback", name="feedback", description="Submit a feedback for the owners of the bot"
description="Submit a feedback for the owners of the bot"
) )
async def feedback(self, context): async def feedback(self, context):
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
@@ -34,7 +35,10 @@ def feedback_command():
title="Thank You!", title="Thank You!",
description="Your feedback has been submitted, the owners have been notified about it.", description="Your feedback has been submitted, the owners have been notified about it.",
color=0x7289DA, color=0x7289DA,
).set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/gSxqzV.png"), ).set_author(
name="Feedback System",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
),
ephemeral=True, ephemeral=True,
) )
@@ -44,7 +48,10 @@ def feedback_command():
title="New Feedback", title="New Feedback",
description=f"{interaction.user} (<@{interaction.user.id}>) has submitted a new feedback:\n```\n{feedback_form.answer}\n```", description=f"{interaction.user} (<@{interaction.user.id}>) has submitted a new feedback:\n```\n{feedback_form.answer}\n```",
color=0x7289DA, color=0x7289DA,
).set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/gSxqzV.png") ).set_author(
name="Feedback System",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
)
) )
else: else:
embed = discord.Embed( embed = discord.Embed(
@@ -52,7 +59,10 @@ def feedback_command():
description="This command can only be used as a slash command. Please use `/general feedback` instead.", description="This command can only be used as a slash command. Please use `/general feedback` instead.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/gSxqzV.png") embed.set_author(
name="Feedback System",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
)
await context.send(embed=embed) await context.send(embed=embed)
return feedback return feedback

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
def ping_command(): def ping_command():
@commands.hybrid_command( @commands.hybrid_command(
name="ping", name="ping",
@@ -12,7 +13,9 @@ def ping_command():
description=f"The bot latency is {round(self.bot.latency * 1000)}ms.", description=f"The bot latency is {round(self.bot.latency * 1000)}ms.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Ping", icon_url="https://yes.nighty.works/raw/gSxqzV.png") embed.set_author(
name="Ping", icon_url="https://yes.nighty.works/raw/gSxqzV.png"
)
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction
if not inter.response.is_done(): if not inter.response.is_done():

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
def serverinfo_command(): def serverinfo_command():
@commands.hybrid_command( @commands.hybrid_command(
name="serverinfo", name="serverinfo",
@@ -14,14 +15,32 @@ def serverinfo_command():
guild = context.guild guild = context.guild
text_channels = len([c for c in guild.channels if isinstance(c, discord.TextChannel)]) text_channels = len(
voice_channels = len([c for c in guild.channels if isinstance(c, discord.VoiceChannel)]) [c for c in guild.channels if isinstance(c, discord.TextChannel)]
category_channels = len([c for c in guild.channels if isinstance(c, discord.CategoryChannel)]) )
forum_channels = len([c for c in guild.channels if isinstance(c, discord.ForumChannel)]) voice_channels = len(
stage_channels = len([c for c in guild.channels if isinstance(c, discord.StageChannel)]) [c for c in guild.channels if isinstance(c, discord.VoiceChannel)]
)
category_channels = len(
[c for c in guild.channels if isinstance(c, discord.CategoryChannel)]
)
forum_channels = len(
[c for c in guild.channels if isinstance(c, discord.ForumChannel)]
)
stage_channels = len(
[c for c in guild.channels if isinstance(c, discord.StageChannel)]
)
age_restricted = len([c for c in guild.channels if hasattr(c, 'nsfw') and c.nsfw]) age_restricted = len(
hidden_channels = len([c for c in guild.channels if c.permissions_for(guild.default_role).view_channel == False]) [c for c in guild.channels if hasattr(c, "nsfw") and c.nsfw]
)
hidden_channels = len(
[
c
for c in guild.channels
if c.permissions_for(guild.default_role).view_channel == False
]
)
managed_roles = len([r for r in guild.roles if r.managed]) managed_roles = len([r for r in guild.roles if r.managed])
@@ -29,15 +48,29 @@ def serverinfo_command():
managed_emojis = len([e for e in guild.emojis if e.managed]) managed_emojis = len([e for e in guild.emojis if e.managed])
unavailable_emojis = len([e for e in guild.emojis if not e.available]) unavailable_emojis = len([e for e in guild.emojis if not e.available])
png_stickers = len([s for s in guild.stickers if s.format == discord.StickerFormatType.png]) png_stickers = len(
apng_stickers = len([s for s in guild.stickers if s.format == discord.StickerFormatType.apng]) [s for s in guild.stickers if s.format == discord.StickerFormatType.png]
gif_stickers = len([s for s in guild.stickers if s.format == discord.StickerFormatType.lottie]) )
lottie_stickers = len([s for s in guild.stickers if s.format == discord.StickerFormatType.lottie]) apng_stickers = len(
[s for s in guild.stickers if s.format == discord.StickerFormatType.apng]
)
gif_stickers = len(
[s for s in guild.stickers if s.format == discord.StickerFormatType.lottie]
)
lottie_stickers = len(
[s for s in guild.stickers if s.format == discord.StickerFormatType.lottie]
)
online_members = len([m for m in guild.members if m.status == discord.Status.online]) online_members = len(
idle_members = len([m for m in guild.members if m.status == discord.Status.idle]) [m for m in guild.members if m.status == discord.Status.online]
)
idle_members = len(
[m for m in guild.members if m.status == discord.Status.idle]
)
dnd_members = len([m for m in guild.members if m.status == discord.Status.dnd]) dnd_members = len([m for m in guild.members if m.status == discord.Status.dnd])
offline_members = len([m for m in guild.members if m.status == discord.Status.offline]) offline_members = len(
[m for m in guild.members if m.status == discord.Status.offline]
)
bot_count = len([m for m in guild.members if m.bot]) bot_count = len([m for m in guild.members if m.bot])
human_count = guild.member_count - bot_count human_count = guild.member_count - bot_count
@@ -46,30 +79,32 @@ def serverinfo_command():
years_ago = created_delta.days // 365 years_ago = created_delta.days // 365
embed = discord.Embed( embed = discord.Embed(
title=f"**Server Name:** {guild.name}", title=f"**Server Name:** {guild.name}", color=0x7289DA
color=0x7289DA ).set_author(
).set_author(name="Server Information", icon_url="https://yes.nighty.works/raw/gSxqzV.png") name="Server Information",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
)
if guild.icon is not None: if guild.icon is not None:
embed.set_thumbnail(url=guild.icon.url) embed.set_thumbnail(url=guild.icon.url)
owner_value = guild.owner.mention if guild.owner else (f"<@{guild.owner_id}>" if guild.owner_id else "Unknown") owner_value = (
embed.add_field( guild.owner.mention
name="Owner", if guild.owner
value=owner_value, else (f"<@{guild.owner_id}>" if guild.owner_id else "Unknown")
inline=True
) )
embed.add_field(name="Owner", value=owner_value, inline=True)
embed.add_field( embed.add_field(
name="Created", name="Created",
value=f"{years_ago} year{'s' if years_ago != 1 else ''} ago", value=f"{years_ago} year{'s' if years_ago != 1 else ''} ago",
inline=True inline=True,
) )
embed.add_field( embed.add_field(
name="Max Members", name="Max Members",
value=f"{guild.max_members:,}" if guild.max_members else "Unknown", value=f"{guild.max_members:,}" if guild.max_members else "Unknown",
inline=True inline=True,
) )
boost_level = guild.premium_tier boost_level = guild.premium_tier
@@ -77,7 +112,7 @@ def serverinfo_command():
embed.add_field( embed.add_field(
name="Boost Status", name="Boost Status",
value=f"Level {boost_level}, {boost_count} Boost{'s' if boost_count != 1 else ''}", value=f"Level {boost_level}, {boost_count} Boost{'s' if boost_count != 1 else ''}",
inline=False inline=False,
) )
channels_info = f"{text_channels} text, {voice_channels} voice, {category_channels} category" channels_info = f"{text_channels} text, {voice_channels} voice, {category_channels} category"
@@ -88,25 +123,19 @@ def serverinfo_command():
channels_info += f"\n{age_restricted} age restricted, {hidden_channels} hidden" channels_info += f"\n{age_restricted} age restricted, {hidden_channels} hidden"
embed.add_field( embed.add_field(
name=f"Channels ({len(guild.channels)})", name=f"Channels ({len(guild.channels)})", value=channels_info, inline=True
value=channels_info,
inline=True
) )
roles_info = f"{len(guild.roles)} total\n{managed_roles} managed" roles_info = f"{len(guild.roles)} total\n{managed_roles} managed"
embed.add_field( embed.add_field(
name=f"Roles ({len(guild.roles)})", name=f"Roles ({len(guild.roles)})", value=roles_info, inline=True
value=roles_info,
inline=True
) )
emotes_info = f"{len(guild.emojis)} total\n{animated_emojis} animated, {managed_emojis} managed" emotes_info = f"{len(guild.emojis)} total\n{animated_emojis} animated, {managed_emojis} managed"
if unavailable_emojis > 0: if unavailable_emojis > 0:
emotes_info += f"\n{unavailable_emojis} unavailable" emotes_info += f"\n{unavailable_emojis} unavailable"
embed.add_field( embed.add_field(
name=f"Emotes ({len(guild.emojis)})", name=f"Emotes ({len(guild.emojis)})", value=emotes_info, inline=True
value=emotes_info,
inline=True
) )
if len(guild.stickers) > 0: if len(guild.stickers) > 0:
@@ -114,19 +143,21 @@ def serverinfo_command():
embed.add_field( embed.add_field(
name=f"Stickers ({len(guild.stickers)})", name=f"Stickers ({len(guild.stickers)})",
value=stickers_info, value=stickers_info,
inline=True inline=True,
) )
embed.add_field( embed.add_field(
name="Member Count", name="Member Count", value=f"{guild.member_count}", inline=False
value=f"{guild.member_count}",
inline=False
) )
embed.set_footer(text=f"Server ID: {guild.id} • Created: {guild.created_at.strftime('%m/%d/%Y')}") embed.set_footer(
text=f"Server ID: {guild.id} • Created: {guild.created_at.strftime('%m/%d/%Y')}"
)
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
await context.interaction.response.send_message(embed=embed, ephemeral=False) await context.interaction.response.send_message(
embed=embed, ephemeral=False
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)

View File

@@ -1,21 +1,29 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
class UptimeView(discord.ui.View): class UptimeView(discord.ui.View):
def __init__(self, bot): def __init__(self, bot):
super().__init__(timeout=300) super().__init__(timeout=300)
self.bot = bot self.bot = bot
@discord.ui.button(emoji="<:RefreshEmoji:1418934990770802891>", style=discord.ButtonStyle.primary) @discord.ui.button(
async def refresh_button(self, interaction: discord.Interaction, button: discord.ui.Button): emoji="<:RefreshEmoji:1418934990770802891>", style=discord.ButtonStyle.primary
)
async def refresh_button(
self, interaction: discord.Interaction, button: discord.ui.Button
):
embed = discord.Embed( embed = discord.Embed(
title="Bot Uptime", title="Bot Uptime",
description=f"The bot has been running for {self.bot.get_uptime()}", description=f"The bot has been running for {self.bot.get_uptime()}",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Uptime", icon_url="https://yes.nighty.works/raw/gSxqzV.png") embed.set_author(
name="Uptime", icon_url="https://yes.nighty.works/raw/gSxqzV.png"
)
await interaction.response.edit_message(embed=embed, view=self) await interaction.response.edit_message(embed=embed, view=self)
def uptime_command(): def uptime_command():
@commands.hybrid_command( @commands.hybrid_command(
name="uptime", name="uptime",
@@ -27,12 +35,16 @@ def uptime_command():
description=f"The bot has been running for **{self.bot.get_uptime()}**", description=f"The bot has been running for **{self.bot.get_uptime()}**",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Uptime", icon_url="https://yes.nighty.works/raw/gSxqzV.png") embed.set_author(
name="Uptime", icon_url="https://yes.nighty.works/raw/gSxqzV.png"
)
view = UptimeView(self.bot) view = UptimeView(self.bot)
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction
if not inter.response.is_done(): if not inter.response.is_done():
await inter.response.send_message(embed=embed, view=view, ephemeral=True) await inter.response.send_message(
embed=embed, view=view, ephemeral=True
)
else: else:
await inter.followup.send(embed=embed, view=view, ephemeral=True) await inter.followup.send(embed=embed, view=view, ephemeral=True)
else: else:

View File

@@ -20,161 +20,166 @@ ACTIVITY_TYPE_NAMES = [
"Watching", "Watching",
"Custom Status", "Custom Status",
"Competing in", "Competing in",
"Hang Status" "Hang Status",
] ]
USER_FLAGS = { USER_FLAGS = {
'STAFF': 1 << 0, "STAFF": 1 << 0,
'PARTNER': 1 << 1, "PARTNER": 1 << 1,
'HYPESQUAD': 1 << 2, "HYPESQUAD": 1 << 2,
'BUG_HUNTER_LEVEL_1': 1 << 3, "BUG_HUNTER_LEVEL_1": 1 << 3,
'HYPESQUAD_ONLINE_HOUSE_1': 1 << 6, "HYPESQUAD_ONLINE_HOUSE_1": 1 << 6,
'HYPESQUAD_ONLINE_HOUSE_2': 1 << 7, "HYPESQUAD_ONLINE_HOUSE_2": 1 << 7,
'HYPESQUAD_ONLINE_HOUSE_3': 1 << 8, "HYPESQUAD_ONLINE_HOUSE_3": 1 << 8,
'PREMIUM_EARLY_SUPPORTER': 1 << 9, "PREMIUM_EARLY_SUPPORTER": 1 << 9,
'BUG_HUNTER_LEVEL_2': 1 << 14, "BUG_HUNTER_LEVEL_2": 1 << 14,
'VERIFIED_DEVELOPER': 1 << 17, "VERIFIED_DEVELOPER": 1 << 17,
'CERTIFIED_MODERATOR': 1 << 18, "CERTIFIED_MODERATOR": 1 << 18,
'ACTIVE_DEVELOPER': 1 << 22 "ACTIVE_DEVELOPER": 1 << 22,
} }
APPLICATION_FLAGS = { APPLICATION_FLAGS = {
'APPLICATION_COMMAND_BADGE': 1 << 23, "APPLICATION_COMMAND_BADGE": 1 << 23,
'AUTO_MODERATION_RULE_CREATE_BADGE': 1 << 6 "AUTO_MODERATION_RULE_CREATE_BADGE": 1 << 6,
} }
BADGE_URLS = { BADGE_URLS = {
'staff': 'https://discord.com/company', "staff": "https://discord.com/company",
'partner': 'https://discord.com/partners', "partner": "https://discord.com/partners",
'certified_moderator': 'https://discord.com/safety', "certified_moderator": "https://discord.com/safety",
'hypesquad': 'https://discord.com/hypesquad', "hypesquad": "https://discord.com/hypesquad",
'hypesquad_house_1': 'https://discord.com/settings/hypesquad-online', "hypesquad_house_1": "https://discord.com/settings/hypesquad-online",
'hypesquad_house_2': 'https://discord.com/settings/hypesquad-online', "hypesquad_house_2": "https://discord.com/settings/hypesquad-online",
'hypesquad_house_3': 'https://discord.com/settings/hypesquad-online', "hypesquad_house_3": "https://discord.com/settings/hypesquad-online",
'bug_hunter_level_1': 'https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs', "bug_hunter_level_1": "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs",
'bug_hunter_level_2': 'https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs', "bug_hunter_level_2": "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs",
'active_developer': 'https://support-dev.discord.com/hc/en-us/articles/10113997751447?ref=badge', "active_developer": "https://support-dev.discord.com/hc/en-us/articles/10113997751447?ref=badge",
'early_supporter': 'https://discord.com/settings/premium', "early_supporter": "https://discord.com/settings/premium",
'premium': 'https://discord.com/settings/premium', "premium": "https://discord.com/settings/premium",
'bot_commands': 'https://discord.com/blog/welcome-to-the-new-era-of-discord-apps?ref=badge', "bot_commands": "https://discord.com/blog/welcome-to-the-new-era-of-discord-apps?ref=badge",
'quest_completed': 'https://discord.com/settings/inventory' "quest_completed": "https://discord.com/settings/inventory",
} }
BADGE_ICONS = { BADGE_ICONS = {
'staff': '<:discordstaff:1426051878155845702>', "staff": "<:discordstaff:1426051878155845702>",
'partner': '<:discordpartner:1426051933608873986>', "partner": "<:discordpartner:1426051933608873986>",
'certified_moderator': '<:discordmod:1426051921826943050>', "certified_moderator": "<:discordmod:1426051921826943050>",
'hypesquad': '<:hypesquadevents:1426051833536970852>', "hypesquad": "<:hypesquadevents:1426051833536970852>",
'hypesquad_house_1': '<:hypesquadbravery:1426051916739383297>', "hypesquad_house_1": "<:hypesquadbravery:1426051916739383297>",
'hypesquad_house_2': '<:hypesquadbrilliance:1426051849433387068>', "hypesquad_house_2": "<:hypesquadbrilliance:1426051849433387068>",
'hypesquad_house_3': '<:hypesquadbalance:1426051905179750495>', "hypesquad_house_3": "<:hypesquadbalance:1426051905179750495>",
'bug_hunter_level_1': '<:discordbughunter1:1426052002193997895>', "bug_hunter_level_1": "<:discordbughunter1:1426052002193997895>",
'bug_hunter_level_2': '<:discordbughunter2:1426052028257406987>', "bug_hunter_level_2": "<:discordbughunter2:1426052028257406987>",
'active_developer': '<:activedeveloper:1426051981658685552>', "active_developer": "<:activedeveloper:1426051981658685552>",
'verified_developer': '<:discordbotdev:1426051827077480570>', "verified_developer": "<:discordbotdev:1426051827077480570>",
'early_supporter': '<:discordearlysupporter:1426052023165517924>', "early_supporter": "<:discordearlysupporter:1426052023165517924>",
'premium': '<:discordnitro:1426051911123206296>', "premium": "<:discordnitro:1426051911123206296>",
'guild_booster_lvl1': '<:discordboost1:1426052007294144605>', "guild_booster_lvl1": "<:discordboost1:1426052007294144605>",
'guild_booster_lvl2': '<:discordboost2:1426051986985582692>', "guild_booster_lvl2": "<:discordboost2:1426051986985582692>",
'guild_booster_lvl3': '<:discordboost3:1426051991812964434>', "guild_booster_lvl3": "<:discordboost3:1426051991812964434>",
'guild_booster_lvl4': '<:discordboost4:1426051955473645671>', "guild_booster_lvl4": "<:discordboost4:1426051955473645671>",
'guild_booster_lvl5': '<:discordboost5:1426051960456609824>', "guild_booster_lvl5": "<:discordboost5:1426051960456609824>",
'guild_booster_lvl6': '<:discordboost6:1426051976583712918>', "guild_booster_lvl6": "<:discordboost6:1426051976583712918>",
'guild_booster_lvl7': '<:discordboost7:1426051965808410634>', "guild_booster_lvl7": "<:discordboost7:1426051965808410634>",
'guild_booster_lvl8': '<:discordboost8:1426051844014342225>', "guild_booster_lvl8": "<:discordboost8:1426051844014342225>",
'guild_booster_lvl9': '<:discordboost9:1426051855015743558>', "guild_booster_lvl9": "<:discordboost9:1426051855015743558>",
'bot_commands': '<:supportscommands:1426051872476889171>', "bot_commands": "<:supportscommands:1426051872476889171>",
'automod': '<:automod:1426051939103146115>', "automod": "<:automod:1426051939103146115>",
'quest_completed': '<:quest:1426051817946611784>', "quest_completed": "<:quest:1426051817946611784>",
'username': '<:username:1426051894371160115>', "username": "<:username:1426051894371160115>",
'premium_bot': '<:premiumbot:1426051888272638025>', "premium_bot": "<:premiumbot:1426051888272638025>",
'orb': '<:orb:1426051861605126289>', "orb": "<:orb:1426051861605126289>",
'bronze': '<:bronze:1426051866969772034>', "bronze": "<:bronze:1426051866969772034>",
'silver': '<:silver:1426051928575709286>', "silver": "<:silver:1426051928575709286>",
'gold': '<:gold:1426052012352737333>', "gold": "<:gold:1426052012352737333>",
'platinum': '<:platinum:1426052018040082545>', "platinum": "<:platinum:1426052018040082545>",
'diamond': '<:diamond:1426051944685895771>', "diamond": "<:diamond:1426051944685895771>",
'emerald': '<:emerald:1426051812313792537>', "emerald": "<:emerald:1426051812313792537>",
'ruby': '<:ruby:1426051838645637150>', "ruby": "<:ruby:1426051838645637150>",
'opal': '<:opal:1426051883247603762>' "opal": "<:opal:1426051883247603762>",
} }
ACTIVITY_TYPE_ICONS = { ACTIVITY_TYPE_ICONS = {
0: '<:gaming:1426409065701048451>', 0: "<:gaming:1426409065701048451>",
2: '<:music:1426409047132737586>', 2: "<:music:1426409047132737586>",
3: '<:watching:1426409475450863778>' 3: "<:watching:1426409475450863778>",
} }
def format_username(user): def format_username(user):
if user.discriminator and user.discriminator != '0': if user.discriminator and user.discriminator != "0":
return f'{user.name}#{user.discriminator}' return f"{user.name}#{user.discriminator}"
return f'@{user.name}' return f"@{user.name}"
def get_default_avatar(user_id, discriminator=None): def get_default_avatar(user_id, discriminator=None):
if discriminator and int(discriminator) > 0: if discriminator and int(discriminator) > 0:
index = int(discriminator) % 5 index = int(discriminator) % 5
else: else:
index = (int(user_id) >> 22) % 6 index = (int(user_id) >> 22) % 6
return f'https://cdn.discordapp.com/embed/avatars/{index}.png' return f"https://cdn.discordapp.com/embed/avatars/{index}.png"
def snowflake_to_timestamp(snowflake): def snowflake_to_timestamp(snowflake):
return ((int(snowflake) >> 22) + 1420070400000) / 1000 return ((int(snowflake) >> 22) + 1420070400000) / 1000
async def fetch_quest_data(): async def fetch_quest_data():
global quests_fetch, quest_data global quests_fetch, quest_data
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
'https://raw.githubusercontent.com/aamiaa/discord-api-diff/refs/heads/main/quests.json' "https://raw.githubusercontent.com/aamiaa/discord-api-diff/refs/heads/main/quests.json"
) as resp: ) as resp:
quest_data = await resp.json() quest_data = await resp.json()
quests_fetch = int(datetime.now().timestamp() * 1000) + 3600000 quests_fetch = int(datetime.now().timestamp() * 1000) + 3600000
async def get_user_data(bot, user_id): async def get_user_data(bot, user_id):
headers = {'Authorization': f'Bot {bot.http.token}'} headers = {"Authorization": f"Bot {bot.http.token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
f'https://discord.com/api/v10/users/{user_id}', f"https://discord.com/api/v10/users/{user_id}", headers=headers
headers=headers
) as resp: ) as resp:
if resp.status == 404: if resp.status == 404:
return None return None
return await resp.json() return await resp.json()
async def get_application_data(bot, app_id): async def get_application_data(bot, app_id):
headers = {'Authorization': f'Bot {bot.http.token}'} headers = {"Authorization": f"Bot {bot.http.token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
f'https://discord.com/api/v10/applications/{app_id}/rpc', f"https://discord.com/api/v10/applications/{app_id}/rpc", headers=headers
headers=headers
) as resp: ) as resp:
if resp.status in [404, 403, 10002]: if resp.status in [404, 403, 10002]:
return None return None
return await resp.json() return await resp.json()
async def get_published_listing(bot, sku_id): async def get_published_listing(bot, sku_id):
headers = {'Authorization': f'Bot {bot.http.token}'} headers = {"Authorization": f"Bot {bot.http.token}"}
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
f'https://discord.com/api/v10/store/published-listings/skus/{sku_id}', f"https://discord.com/api/v10/store/published-listings/skus/{sku_id}",
headers=headers headers=headers,
) as resp: ) as resp:
if resp.status != 200: if resp.status != 200:
return None return None
return await resp.json() return await resp.json()
def userinfo_command(): def userinfo_command():
@commands.hybrid_command( @commands.hybrid_command(
name="userinfo", name="userinfo",
description="Get information on a user.", description="Get information on a user.",
) )
@app_commands.describe( @app_commands.describe(
user="User to get info for", user="User to get info for", user_id="User ID to get info for"
user_id="User ID to get info for"
) )
async def userinfo(self, context, user: discord.User = None, user_id: str = None): async def userinfo(self, context, user: discord.User = None, user_id: str = None):
await context.defer() await context.defer()
@@ -186,12 +191,12 @@ def userinfo_command():
try: try:
target_user = await bot.fetch_user(int(user_id)) target_user = await bot.fetch_user(int(user_id))
except: except:
await context.send('User not found.') await context.send("User not found.")
return return
user_data = await get_user_data(bot, target_user.id) user_data = await get_user_data(bot, target_user.id)
if not user_data: if not user_data:
await context.send('Failed to fetch user data.') await context.send("Failed to fetch user data.")
return return
guild = context.guild guild = context.guild
@@ -204,153 +209,203 @@ def userinfo_command():
pass pass
badges = [] badges = []
flags = user_data.get('public_flags', 0) flags = user_data.get("public_flags", 0)
if str(target_user.id) == '1015372540937502851': if str(target_user.id) == "1015372540937502851":
badges.append(f"[{BADGE_ICONS['staff']}]({BADGE_URLS['staff']})") badges.append(f"[{BADGE_ICONS['staff']}]({BADGE_URLS['staff']})")
badges.append(f"[{BADGE_ICONS['partner']}]({BADGE_URLS['partner']})") badges.append(f"[{BADGE_ICONS['partner']}]({BADGE_URLS['partner']})")
badges.append(f"[{BADGE_ICONS['certified_moderator']}]({BADGE_URLS['certified_moderator']})") badges.append(
badges.append(f"[{BADGE_ICONS['hypesquad_house_1']}]({BADGE_URLS['hypesquad_house_1']})") f"[{BADGE_ICONS['certified_moderator']}]({BADGE_URLS['certified_moderator']})"
badges.append(f"[{BADGE_ICONS['bug_hunter_level_2']}]({BADGE_URLS['bug_hunter_level_2']})") )
badges.append(BADGE_ICONS['verified_developer']) badges.append(
badges.append(f"[{BADGE_ICONS['early_supporter']}]({BADGE_URLS['early_supporter']})") f"[{BADGE_ICONS['hypesquad_house_1']}]({BADGE_URLS['hypesquad_house_1']})"
badges.append(f"[{BADGE_ICONS['guild_booster_lvl9']}]({BADGE_URLS['premium']})") )
badges.append(f"[{BADGE_ICONS['quest_completed']}]({BADGE_URLS['quest_completed']})") badges.append(
badges.append(BADGE_ICONS['username']) f"[{BADGE_ICONS['bug_hunter_level_2']}]({BADGE_URLS['bug_hunter_level_2']})"
elif str(target_user.id) == '1376728824108286034': )
badges.append(BADGE_ICONS['automod']) badges.append(BADGE_ICONS["verified_developer"])
badges.append(BADGE_ICONS['verified_developer']) badges.append(
badges.append(BADGE_ICONS['premium_bot']) f"[{BADGE_ICONS['early_supporter']}]({BADGE_URLS['early_supporter']})"
elif flags & USER_FLAGS['STAFF']: )
badges.append(
f"[{BADGE_ICONS['guild_booster_lvl9']}]({BADGE_URLS['premium']})"
)
badges.append(
f"[{BADGE_ICONS['quest_completed']}]({BADGE_URLS['quest_completed']})"
)
badges.append(BADGE_ICONS["username"])
elif str(target_user.id) == "1376728824108286034":
badges.append(BADGE_ICONS["automod"])
badges.append(BADGE_ICONS["verified_developer"])
badges.append(BADGE_ICONS["premium_bot"])
elif flags & USER_FLAGS["STAFF"]:
badges.append(f"[{BADGE_ICONS['staff']}]({BADGE_URLS['staff']})") badges.append(f"[{BADGE_ICONS['staff']}]({BADGE_URLS['staff']})")
if flags & USER_FLAGS['PARTNER']: if flags & USER_FLAGS["PARTNER"]:
badges.append(f"[{BADGE_ICONS['partner']}]({BADGE_URLS['partner']})") badges.append(f"[{BADGE_ICONS['partner']}]({BADGE_URLS['partner']})")
if flags & USER_FLAGS['CERTIFIED_MODERATOR']: if flags & USER_FLAGS["CERTIFIED_MODERATOR"]:
badges.append(f"[{BADGE_ICONS['certified_moderator']}]({BADGE_URLS['certified_moderator']})") badges.append(
if flags & USER_FLAGS['HYPESQUAD']: f"[{BADGE_ICONS['certified_moderator']}]({BADGE_URLS['certified_moderator']})"
)
if flags & USER_FLAGS["HYPESQUAD"]:
badges.append(f"[{BADGE_ICONS['hypesquad']}]({BADGE_URLS['hypesquad']})") badges.append(f"[{BADGE_ICONS['hypesquad']}]({BADGE_URLS['hypesquad']})")
if flags & USER_FLAGS['HYPESQUAD_ONLINE_HOUSE_1']: if flags & USER_FLAGS["HYPESQUAD_ONLINE_HOUSE_1"]:
badges.append(f"[{BADGE_ICONS['hypesquad_house_1']}]({BADGE_URLS['hypesquad_house_1']})") badges.append(
if flags & USER_FLAGS['HYPESQUAD_ONLINE_HOUSE_2']: f"[{BADGE_ICONS['hypesquad_house_1']}]({BADGE_URLS['hypesquad_house_1']})"
badges.append(f"[{BADGE_ICONS['hypesquad_house_2']}]({BADGE_URLS['hypesquad_house_2']})") )
if flags & USER_FLAGS['HYPESQUAD_ONLINE_HOUSE_3']: if flags & USER_FLAGS["HYPESQUAD_ONLINE_HOUSE_2"]:
badges.append(f"[{BADGE_ICONS['hypesquad_house_3']}]({BADGE_URLS['hypesquad_house_3']})") badges.append(
if flags & USER_FLAGS['BUG_HUNTER_LEVEL_1']: f"[{BADGE_ICONS['hypesquad_house_2']}]({BADGE_URLS['hypesquad_house_2']})"
badges.append(f"[{BADGE_ICONS['bug_hunter_level_1']}]({BADGE_URLS['bug_hunter_level_1']})") )
if flags & USER_FLAGS['BUG_HUNTER_LEVEL_2']: if flags & USER_FLAGS["HYPESQUAD_ONLINE_HOUSE_3"]:
badges.append(f"[{BADGE_ICONS['bug_hunter_level_2']}]({BADGE_URLS['bug_hunter_level_2']})") badges.append(
if flags & USER_FLAGS['ACTIVE_DEVELOPER']: f"[{BADGE_ICONS['hypesquad_house_3']}]({BADGE_URLS['hypesquad_house_3']})"
badges.append(f"[{BADGE_ICONS['active_developer']}]({BADGE_URLS['active_developer']})") )
if flags & USER_FLAGS['VERIFIED_DEVELOPER']: if flags & USER_FLAGS["BUG_HUNTER_LEVEL_1"]:
badges.append(BADGE_ICONS['verified_developer']) badges.append(
if flags & USER_FLAGS['PREMIUM_EARLY_SUPPORTER']: f"[{BADGE_ICONS['bug_hunter_level_1']}]({BADGE_URLS['bug_hunter_level_1']})"
badges.append(f"[{BADGE_ICONS['early_supporter']}]({BADGE_URLS['early_supporter']})") )
if flags & USER_FLAGS["BUG_HUNTER_LEVEL_2"]:
badges.append(
f"[{BADGE_ICONS['bug_hunter_level_2']}]({BADGE_URLS['bug_hunter_level_2']})"
)
if flags & USER_FLAGS["ACTIVE_DEVELOPER"]:
badges.append(
f"[{BADGE_ICONS['active_developer']}]({BADGE_URLS['active_developer']})"
)
if flags & USER_FLAGS["VERIFIED_DEVELOPER"]:
badges.append(BADGE_ICONS["verified_developer"])
if flags & USER_FLAGS["PREMIUM_EARLY_SUPPORTER"]:
badges.append(
f"[{BADGE_ICONS['early_supporter']}]({BADGE_URLS['early_supporter']})"
)
avatar_hash = user_data.get('avatar', '') avatar_hash = user_data.get("avatar", "")
banner_hash = user_data.get('banner') banner_hash = user_data.get("banner")
if (banner_hash or (avatar_hash and avatar_hash.startswith('a_'))) and not user_data.get('bot'): if (
banner_hash or (avatar_hash and avatar_hash.startswith("a_"))
) and not user_data.get("bot"):
badges.append(f"[{BADGE_ICONS['premium']}]({BADGE_URLS['premium']})") badges.append(f"[{BADGE_ICONS['premium']}]({BADGE_URLS['premium']})")
if member and member.premium_since: if member and member.premium_since:
boosting_since = member.premium_since boosting_since = member.premium_since
delta = (datetime.now(timezone.utc) - boosting_since).total_seconds() delta = (datetime.now(timezone.utc) - boosting_since).total_seconds()
icon = BADGE_ICONS['guild_booster_lvl1'] icon = BADGE_ICONS["guild_booster_lvl1"]
if delta >= ONE_MONTH * 24: if delta >= ONE_MONTH * 24:
icon = BADGE_ICONS['guild_booster_lvl9'] icon = BADGE_ICONS["guild_booster_lvl9"]
elif delta >= ONE_MONTH * 18: elif delta >= ONE_MONTH * 18:
icon = BADGE_ICONS['guild_booster_lvl8'] icon = BADGE_ICONS["guild_booster_lvl8"]
elif delta >= ONE_MONTH * 15: elif delta >= ONE_MONTH * 15:
icon = BADGE_ICONS['guild_booster_lvl7'] icon = BADGE_ICONS["guild_booster_lvl7"]
elif delta >= ONE_MONTH * 12: elif delta >= ONE_MONTH * 12:
icon = BADGE_ICONS['guild_booster_lvl6'] icon = BADGE_ICONS["guild_booster_lvl6"]
elif delta >= ONE_MONTH * 9: elif delta >= ONE_MONTH * 9:
icon = BADGE_ICONS['guild_booster_lvl5'] icon = BADGE_ICONS["guild_booster_lvl5"]
elif delta >= ONE_MONTH * 6: elif delta >= ONE_MONTH * 6:
icon = BADGE_ICONS['guild_booster_lvl4'] icon = BADGE_ICONS["guild_booster_lvl4"]
elif delta >= ONE_MONTH * 3: elif delta >= ONE_MONTH * 3:
icon = BADGE_ICONS['guild_booster_lvl3'] icon = BADGE_ICONS["guild_booster_lvl3"]
elif delta >= ONE_MONTH * 2: elif delta >= ONE_MONTH * 2:
icon = BADGE_ICONS['guild_booster_lvl2'] icon = BADGE_ICONS["guild_booster_lvl2"]
badges.append(f"[{icon}]({BADGE_URLS['premium']})") badges.append(f"[{icon}]({BADGE_URLS['premium']})")
bot_deleted = False bot_deleted = False
if user_data.get('bot'): if user_data.get("bot"):
app_data = await get_application_data(bot, target_user.id) app_data = await get_application_data(bot, target_user.id)
if app_data: if app_data:
app_flags = app_data.get('flags', 0) app_flags = app_data.get("flags", 0)
if app_flags & APPLICATION_FLAGS['APPLICATION_COMMAND_BADGE']: if app_flags & APPLICATION_FLAGS["APPLICATION_COMMAND_BADGE"]:
badges.append(f"[{BADGE_ICONS['bot_commands']}]({BADGE_URLS['bot_commands']})") badges.append(
if app_flags & APPLICATION_FLAGS['AUTO_MODERATION_RULE_CREATE_BADGE']: f"[{BADGE_ICONS['bot_commands']}]({BADGE_URLS['bot_commands']})"
badges.append(BADGE_ICONS['automod']) )
if app_flags & APPLICATION_FLAGS["AUTO_MODERATION_RULE_CREATE_BADGE"]:
badges.append(BADGE_ICONS["automod"])
else: else:
bot_deleted = True bot_deleted = True
if user_data.get('system'): if user_data.get("system"):
bot_deleted = False bot_deleted = False
quest_decoration_name = None quest_decoration_name = None
avatar_decoration = user_data.get('avatar_decoration_data') avatar_decoration = user_data.get("avatar_decoration_data")
if avatar_decoration and avatar_decoration.get('sku_id'): if avatar_decoration and avatar_decoration.get("sku_id"):
for quest in quest_data: for quest in quest_data:
config = quest.get('config', {}) config = quest.get("config", {})
rewards = config.get('rewards_config', {}).get('rewards', []) or config.get('rewards', []) rewards = config.get("rewards_config", {}).get(
"rewards", []
) or config.get("rewards", [])
for reward in rewards: for reward in rewards:
if reward.get('type') == 3 and reward.get('sku_id') == avatar_decoration['sku_id']: if (
quest_decoration_name = (reward.get('name') or reward.get('messages', {}).get('name') or '*Unknown*').replace('Avatar Decoration', 'Avatar Deco') reward.get("type") == 3
badges.append(f"[{BADGE_ICONS['quest_completed']}]({BADGE_URLS['quest_completed']})") and reward.get("sku_id") == avatar_decoration["sku_id"]
):
quest_decoration_name = (
reward.get("name")
or reward.get("messages", {}).get("name")
or "*Unknown*"
).replace("Avatar Decoration", "Avatar Deco")
badges.append(
f"[{BADGE_ICONS['quest_completed']}]({BADGE_URLS['quest_completed']})"
)
break break
if quest_decoration_name: if quest_decoration_name:
break break
elif avatar_decoration and (avatar_decoration.get('expires_at') or avatar_decoration.get('sku_id') == '1226939756617793606'): elif avatar_decoration and (
badges.append(f"[{BADGE_ICONS['quest_completed']}]({BADGE_URLS['quest_completed']})") avatar_decoration.get("expires_at")
or avatar_decoration.get("sku_id") == "1226939756617793606"
):
badges.append(
f"[{BADGE_ICONS['quest_completed']}]({BADGE_URLS['quest_completed']})"
)
if user_data.get('legacy_username'): if user_data.get("legacy_username"):
badges.append(BADGE_ICONS['username']) badges.append(BADGE_ICONS["username"])
if user_data.get('bot') and user_data.get('approximated_guild_count'): if user_data.get("bot") and user_data.get("approximated_guild_count"):
badges.append(BADGE_ICONS['premium_bot']) badges.append(BADGE_ICONS["premium_bot"])
profile_effect = user_data.get('profile_effect') profile_effect = user_data.get("profile_effect")
if profile_effect: if profile_effect:
effect_id = profile_effect.get('id') effect_id = profile_effect.get("id")
if effect_id: if effect_id:
orb_tier = None orb_tier = None
if '1139323098643333240' in effect_id: if "1139323098643333240" in effect_id:
orb_tier = 'opal' orb_tier = "opal"
elif '1139323095841308733' in effect_id: elif "1139323095841308733" in effect_id:
orb_tier = 'ruby' orb_tier = "ruby"
elif '1139323090842013756' in effect_id: elif "1139323090842013756" in effect_id:
orb_tier = 'emerald' orb_tier = "emerald"
elif '1139323087608832090' in effect_id: elif "1139323087608832090" in effect_id:
orb_tier = 'diamond' orb_tier = "diamond"
elif '1144286544523669516' in effect_id: elif "1144286544523669516" in effect_id:
orb_tier = 'platinum' orb_tier = "platinum"
elif '1139323084127289374' in effect_id: elif "1139323084127289374" in effect_id:
orb_tier = 'gold' orb_tier = "gold"
elif '1139323078435717220' in effect_id: elif "1139323078435717220" in effect_id:
orb_tier = 'silver' orb_tier = "silver"
elif '1139323075214307448' in effect_id: elif "1139323075214307448" in effect_id:
orb_tier = 'bronze' orb_tier = "bronze"
else: else:
orb_tier = 'orb' orb_tier = "orb"
if orb_tier: if orb_tier:
badges.append(BADGE_ICONS[orb_tier]) badges.append(BADGE_ICONS[orb_tier])
default_avatar = get_default_avatar(target_user.id, user_data.get('discriminator', '0')) default_avatar = get_default_avatar(
target_user.id, user_data.get("discriminator", "0")
)
avatar_url = target_user.avatar.url if target_user.avatar else default_avatar avatar_url = target_user.avatar.url if target_user.avatar else default_avatar
banner_url = None banner_url = None
banner_file = None banner_file = None
original_banner_link = None original_banner_link = None
if banner_hash: if banner_hash:
is_animated = banner_hash.startswith('a_') is_animated = banner_hash.startswith("a_")
ext = 'gif' if is_animated else 'png' ext = "gif" if is_animated else "png"
original_banner_url = f'https://cdn.discordapp.com/banners/{target_user.id}/{banner_hash}.{ext}?size=4096' original_banner_url = f"https://cdn.discordapp.com/banners/{target_user.id}/{banner_hash}.{ext}?size=4096"
original_banner_link = original_banner_url original_banner_link = original_banner_url
try: try:
@@ -385,11 +440,18 @@ def userinfo_command():
try: try:
while True: while True:
frame = img.copy().convert('RGBA') frame = img.copy().convert("RGBA")
frame = frame.resize((scale_width, scale_height), Image.Resampling.LANCZOS) frame = frame.resize(
frame = frame.crop((left, top, right, bottom)) (scale_width, scale_height),
Image.Resampling.LANCZOS,
)
frame = frame.crop(
(left, top, right, bottom)
)
frames.append(frame) frames.append(frame)
durations.append(img.info.get('duration', 100)) durations.append(
img.info.get("duration", 100)
)
img.seek(img.tell() + 1) img.seek(img.tell() + 1)
except EOFError: except EOFError:
pass pass
@@ -397,64 +459,77 @@ def userinfo_command():
output = BytesIO() output = BytesIO()
frames[0].save( frames[0].save(
output, output,
format='GIF', format="GIF",
save_all=True, save_all=True,
append_images=frames[1:], append_images=frames[1:],
duration=durations, duration=durations,
loop=0, loop=0,
optimize=False optimize=False,
) )
output.seek(0) output.seek(0)
banner_file = discord.File(output, filename='banner.gif') banner_file = discord.File(
banner_url = 'attachment://banner.gif' output, filename="banner.gif"
)
banner_url = "attachment://banner.gif"
else: else:
img = img.resize((scale_width, scale_height), Image.Resampling.LANCZOS) img = img.resize(
(scale_width, scale_height),
Image.Resampling.LANCZOS,
)
img = img.crop((left, top, right, bottom)) img = img.crop((left, top, right, bottom))
output = BytesIO() output = BytesIO()
img.save(output, format='PNG') img.save(output, format="PNG")
output.seek(0) output.seek(0)
banner_file = discord.File(output, filename='banner.png') banner_file = discord.File(
banner_url = 'attachment://banner.png' output, filename="banner.png"
)
banner_url = "attachment://banner.png"
else: else:
banner_url = original_banner_url banner_url = original_banner_url
except: except:
banner_url = original_banner_url banner_url = original_banner_url
images = [f'[Avatar]({avatar_url})'] images = [f"[Avatar]({avatar_url})"]
if banner_url: if banner_url:
images.append(f'[Banner]({original_banner_link})') images.append(f"[Banner]({original_banner_link})")
if avatar_decoration: if avatar_decoration:
await get_published_listing(bot, avatar_decoration['sku_id']) await get_published_listing(bot, avatar_decoration["sku_id"])
decoration_url = f"https://cdn.discordapp.com/avatar-decoration-presets/{avatar_decoration['asset']}.png?size=4096&passthrough=true" decoration_url = f"https://cdn.discordapp.com/avatar-decoration-presets/{avatar_decoration['asset']}.png?size=4096&passthrough=true"
images.append(f'[Avatar Deco]({decoration_url})') images.append(f"[Avatar Deco]({decoration_url})")
collectibles = user_data.get('collectibles') collectibles = user_data.get("collectibles")
if collectibles and collectibles.get('nameplate'): if collectibles and collectibles.get("nameplate"):
nameplate = collectibles['nameplate'] nameplate = collectibles["nameplate"]
nameplate_asset = nameplate['asset'] nameplate_asset = nameplate["asset"]
images.append(f'[Nameplate](https://cdn.discordapp.com/assets/collectibles/{nameplate_asset}static.png)') images.append(
f"[Nameplate](https://cdn.discordapp.com/assets/collectibles/{nameplate_asset}static.png)"
)
mutual_guilds = [g for g in bot.guilds if g.get_member(target_user.id)] mutual_guilds = [g for g in bot.guilds if g.get_member(target_user.id)]
display_name = user_data.get('global_name') or user_data.get('username') display_name = user_data.get("global_name") or user_data.get("username")
desc_lines = [ desc_lines = [
f"# {member.nick if member and member.nick else display_name}", f"# {member.nick if member and member.nick else display_name}",
f"{format_username(target_user).replace('@', '')} • <@{target_user.id}>" f"{format_username(target_user).replace('@', '')} • <@{target_user.id}>",
] ]
subline = "" subline = ""
if badges: if badges:
subline += ''.join(badges) subline += "".join(badges)
activity_lines = [] activity_lines = []
if member and member.activities: if member and member.activities:
for activity in member.activities: for activity in member.activities:
if activity.type == discord.ActivityType.custom: if activity.type == discord.ActivityType.custom:
activity_lines.append(ACTIVITY_TYPE_NAMES[4]) activity_lines.append(ACTIVITY_TYPE_NAMES[4])
elif activity.type in [discord.ActivityType.playing, discord.ActivityType.listening, discord.ActivityType.watching]: elif activity.type in [
discord.ActivityType.playing,
discord.ActivityType.listening,
discord.ActivityType.watching,
]:
name = activity.name name = activity.name
activity_lines.append( activity_lines.append(
f"{ACTIVITY_TYPE_ICONS.get(activity.type.value, '')} {ACTIVITY_TYPE_NAMES[activity.type.value]} **{name}**".strip() f"{ACTIVITY_TYPE_ICONS.get(activity.type.value, '')} {ACTIVITY_TYPE_NAMES[activity.type.value]} **{name}**".strip()
@@ -464,32 +539,36 @@ def userinfo_command():
desc_lines.append(subline) desc_lines.append(subline)
if mutual_guilds: if mutual_guilds:
desc_lines.append(f"-# {len(mutual_guilds)} Bot Mutual Server{'s' if len(mutual_guilds) > 1 else ''}") desc_lines.append(
f"-# {len(mutual_guilds)} Bot Mutual Server{'s' if len(mutual_guilds) > 1 else ''}"
)
else: else:
desc_lines.append('') desc_lines.append("")
is_system = user_data.get('system') or user_data.get('discriminator') == '0000' is_system = user_data.get("system") or user_data.get("discriminator") == "0000"
if bot_deleted and not is_system: if bot_deleted and not is_system:
desc_lines.append("*This bot's application has been deleted*\n-# (or app ID and user ID desync)") desc_lines.append(
"*This bot's application has been deleted*\n-# (or app ID and user ID desync)"
)
if is_system: if is_system:
desc_lines.append('**System account**') desc_lines.append("**System account**")
desc_lines.append('') desc_lines.append("")
if activity_lines: if activity_lines:
desc_lines.extend(activity_lines) desc_lines.extend(activity_lines)
embed = discord.Embed( embed = discord.Embed(color=0x7289DA, description="\n".join(desc_lines))
color=0x7289DA,
description='\n'.join(desc_lines)
)
primary_guild = user_data.get('primary_guild') primary_guild = user_data.get("primary_guild")
if primary_guild and primary_guild.get('identity_guild_id'): if primary_guild and primary_guild.get("identity_guild_id"):
clan_badge_url = f"https://cdn.discordapp.com/clan-badges/{primary_guild['identity_guild_id']}/{primary_guild['badge']}.png?size=4096" clan_badge_url = f"https://cdn.discordapp.com/clan-badges/{primary_guild['identity_guild_id']}/{primary_guild['badge']}.png?size=4096"
embed.set_author(name=primary_guild.get('tag', ''), icon_url=clan_badge_url) embed.set_author(name=primary_guild.get("tag", ""), icon_url=clan_badge_url)
else: else:
embed.set_author(name="User Information", icon_url="https://yes.nighty.works/raw/gSxqzV.png") embed.set_author(
name="User Information",
icon_url="https://yes.nighty.works/raw/gSxqzV.png",
)
if member and member.nick and member.nick != display_name: if member and member.nick and member.nick != display_name:
embed.title = display_name embed.title = display_name
@@ -502,20 +581,20 @@ def userinfo_command():
created_timestamp = int(snowflake_to_timestamp(target_user.id)) created_timestamp = int(snowflake_to_timestamp(target_user.id))
created_date = f"<t:{created_timestamp}:F>" created_date = f"<t:{created_timestamp}:F>"
embed.add_field(name='Created Date', value=created_date, inline=False) embed.add_field(name="Created Date", value=created_date, inline=False)
if member and hasattr(member, 'joined_at') and member.joined_at: if member and hasattr(member, "joined_at") and member.joined_at:
joined_timestamp = int(member.joined_at.timestamp()) joined_timestamp = int(member.joined_at.timestamp())
join_date = f"<t:{joined_timestamp}:F>" join_date = f"<t:{joined_timestamp}:F>"
embed.add_field(name='Join Date', value=join_date, inline=False) embed.add_field(name="Join Date", value=join_date, inline=False)
is_bot = user_data.get('bot', False) is_bot = user_data.get("bot", False)
embed.add_field(name='Is Bot', value='True' if is_bot else 'False', inline=True) embed.add_field(name="Is Bot", value="True" if is_bot else "False", inline=True)
if member and member.roles[1:]: if member and member.roles[1:]:
roles = sorted(member.roles[1:], key=lambda r: r.position, reverse=True) roles = sorted(member.roles[1:], key=lambda r: r.position, reverse=True)
role_mentions = [f'<@&{r.id}>' for r in roles] role_mentions = [f"<@&{r.id}>" for r in roles]
role_list = ' '.join(role_mentions) role_list = " ".join(role_mentions)
if len(role_list) > 1024: if len(role_list) > 1024:
truncated_roles = [] truncated_roles = []
@@ -525,14 +604,16 @@ def userinfo_command():
break break
truncated_roles.append(mention) truncated_roles.append(mention)
current_length += len(mention) + 1 current_length += len(mention) + 1
role_list = ' '.join(truncated_roles) + ' ...' role_list = " ".join(truncated_roles) + " ..."
embed.add_field(name=f'Roles ({len(member.roles) - 1})', value=role_list, inline=False) embed.add_field(
name=f"Roles ({len(member.roles) - 1})", value=role_list, inline=False
)
if images: if images:
embed.add_field(name='\u200b', value='\u3000'.join(images), inline=False) embed.add_field(name="\u200b", value="\u3000".join(images), inline=False)
embed.set_footer(text=f'ID: {target_user.id}') embed.set_footer(text=f"ID: {target_user.id}")
if banner_file: if banner_file:
await context.send(embed=embed, file=banner_file) await context.send(embed=embed, file=banner_file)
@@ -540,4 +621,3 @@ def userinfo_command():
await context.send(embed=embed) await context.send(embed=embed)
return userinfo return userinfo

View File

@@ -13,15 +13,26 @@ class Help(commands.Cog, name="help"):
interaction: discord.Interaction, interaction: discord.Interaction,
current: str, current: str,
) -> list[app_commands.Choice[str]]: ) -> list[app_commands.Choice[str]]:
categories = ["general", "fun", "moderation", "owner", "sidestore", "idevice", "melonx", "media", "miscellaneous", "utilities", "events"] categories = [
"general",
"fun",
"moderation",
"owner",
"sidestore",
"idevice",
"melonx",
"media",
"miscellaneous",
"utilities",
"events",
]
suggestions = [] suggestions = []
for category in categories: for category in categories:
if current.lower() in category.lower(): if current.lower() in category.lower():
suggestions.append( suggestions.append(
app_commands.Choice( app_commands.Choice(
name=f"{category.capitalize()} Commands", name=f"{category.capitalize()} Commands", value=category
value=category
) )
) )
@@ -35,7 +46,6 @@ class Help(commands.Cog, name="help"):
@app_commands.describe(category="Choose a specific category to view its commands") @app_commands.describe(category="Choose a specific category to view its commands")
@app_commands.autocomplete(category=category_autocomplete) @app_commands.autocomplete(category=category_autocomplete)
async def help(self, context: Context, category: str = None) -> None: async def help(self, context: Context, category: str = None) -> None:
category_mapping = { category_mapping = {
"general": "general", "general": "general",
"fun": "fun", "fun": "fun",
@@ -49,7 +59,6 @@ class Help(commands.Cog, name="help"):
"utils": "utilities", "utils": "utilities",
"utilities": "utilities", "utilities": "utilities",
"events": "events", "events": "events",
"sync": "owner", "sync": "owner",
"logs": "owner", "logs": "owner",
"invite": "owner", "invite": "owner",
@@ -71,26 +80,25 @@ class Help(commands.Cog, name="help"):
"media": "Media commands", "media": "Media commands",
"utilities": "Utility commands", "utilities": "Utility commands",
"miscellaneous": "Miscellaneous commands", "miscellaneous": "Miscellaneous commands",
"events": "Events commands" "events": "Events commands",
} }
if category is None: if category is None:
embed = discord.Embed( embed = discord.Embed(title="Help", color=0x7289DA)
title="Help", embed.set_author(
color=0x7289DA name="Help", icon_url="https://yes.nighty.works/raw/T9mnBO.png"
) )
embed.set_author(name="Help", icon_url="https://yes.nighty.works/raw/T9mnBO.png")
standalone_commands = [] standalone_commands = []
botinfo_cmd = self.bot.tree.get_command("botinfo") botinfo_cmd = self.bot.tree.get_command("botinfo")
if botinfo_cmd: if botinfo_cmd:
standalone_commands.append("**/botinfo** » Get information about this bot") standalone_commands.append(
"**/botinfo** » Get information about this bot"
)
if standalone_commands: if standalone_commands:
embed.add_field( embed.add_field(
name="", name="", value="".join(standalone_commands) + "\n", inline=False
value="".join(standalone_commands) + "\n",
inline=False
) )
available_categories = set() available_categories = set()
@@ -101,18 +109,18 @@ class Help(commands.Cog, name="help"):
category_list = [] category_list = []
for cat in sorted(available_categories): for cat in sorted(available_categories):
description = category_descriptions.get(cat, f"{cat.capitalize()} commands") description = category_descriptions.get(
cat, f"{cat.capitalize()} commands"
)
category_list.append(f"**/help {cat}** » {description}") category_list.append(f"**/help {cat}** » {description}")
if category_list: if category_list:
embed.add_field( embed.add_field(name="", value="\n".join(category_list), inline=False)
name="",
value="\n".join(category_list),
inline=False
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
try: try:
await context.send(embed=embed) await context.send(embed=embed)
@@ -128,10 +136,12 @@ class Help(commands.Cog, name="help"):
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description=f"Category '{category}' not found. Use `/help` to see available categories.", description=f"Category '{category}' not found. Use `/help` to see available categories.",
color=0x7289DA color=0x7289DA,
) )
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
try: try:
await context.send(embed=embed) await context.send(embed=embed)
@@ -142,7 +152,6 @@ class Help(commands.Cog, name="help"):
pass pass
return return
commands_in_category = [] commands_in_category = []
seen_names = set() seen_names = set()
for cog_name in self.bot.cogs: for cog_name in self.bot.cogs:
@@ -151,13 +160,20 @@ class Help(commands.Cog, name="help"):
if cog: if cog:
commands_list = cog.get_commands() commands_list = cog.get_commands()
for command in commands_list: for command in commands_list:
has_prefix_subcommands = hasattr(command, 'commands') and len(getattr(command, 'commands', [])) > 0 has_prefix_subcommands = (
hasattr(command, "commands")
and len(getattr(command, "commands", [])) > 0
)
if has_prefix_subcommands: if has_prefix_subcommands:
continue continue
name = command.name name = command.name
if name in seen_names: if name in seen_names:
continue continue
description = command.description.partition("\n")[0] if command.description else "No description available" description = (
command.description.partition("\n")[0]
if command.description
else "No description available"
)
commands_in_category.append((name, description)) commands_in_category.append((name, description))
seen_names.add(name) seen_names.add(name)
@@ -168,19 +184,32 @@ class Help(commands.Cog, name="help"):
bound_cog_name = getattr(bound_cog, "qualified_name", "").lower() bound_cog_name = getattr(bound_cog, "qualified_name", "").lower()
if category_mapping.get(bound_cog_name) != category: if category_mapping.get(bound_cog_name) != category:
continue continue
has_subcommands = hasattr(app_command, 'commands') and len(getattr(app_command, 'commands', [])) > 0 has_subcommands = (
hasattr(app_command, "commands")
and len(getattr(app_command, "commands", [])) > 0
)
if has_subcommands and category not in ["owner"]: if has_subcommands and category not in ["owner"]:
for subcommand in app_command.commands: for subcommand in app_command.commands:
if subcommand.name in seen_names: if subcommand.name in seen_names:
continue continue
sub_desc = subcommand.description.partition("\n")[0] if getattr(subcommand, "description", None) else "No description available" sub_desc = (
commands_in_category.append((f"{app_command.name} {subcommand.name}", sub_desc)) subcommand.description.partition("\n")[0]
if getattr(subcommand, "description", None)
else "No description available"
)
commands_in_category.append(
(f"{app_command.name} {subcommand.name}", sub_desc)
)
seen_names.add(f"{app_command.name} {subcommand.name}") seen_names.add(f"{app_command.name} {subcommand.name}")
else: else:
if app_command.name in seen_names: if app_command.name in seen_names:
continue continue
description = app_command.description.partition("\n")[0] if getattr(app_command, "description", None) else "No description available" description = (
app_command.description.partition("\n")[0]
if getattr(app_command, "description", None)
else "No description available"
)
commands_in_category.append((app_command.name, description)) commands_in_category.append((app_command.name, description))
seen_names.add(app_command.name) seen_names.add(app_command.name)
@@ -188,10 +217,12 @@ class Help(commands.Cog, name="help"):
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description=f"No commands found in category '{category}'.", description=f"No commands found in category '{category}'.",
color=0x7289DA color=0x7289DA,
) )
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
try: try:
await context.send(embed=embed) await context.send(embed=embed)
@@ -202,20 +233,15 @@ class Help(commands.Cog, name="help"):
pass pass
return return
embed = discord.Embed( embed = discord.Embed(title=f"/help » {category.lower()}", color=0x7289DA)
title=f"/help » {category.lower()}", embed.set_author(
color=0x7289DA name="Help", icon_url="https://yes.nighty.works/raw/T9mnBO.png"
) )
embed.set_author(name="Help", icon_url="https://yes.nighty.works/raw/T9mnBO.png")
data = [] data = []
for command_name, description in sorted(commands_in_category): for command_name, description in sorted(commands_in_category):
data.append(f"**/{command_name}** » {description}") data.append(f"**/{command_name}** » {description}")
help_text = "\n".join(data) help_text = "\n".join(data)
embed.add_field( embed.add_field(name="", value=help_text, inline=False)
name="",
value=help_text,
inline=False
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(embed=embed, ephemeral=True)
else: else:

View File

@@ -22,9 +22,11 @@ class Idevice(commands.GroupCog, name="idevice"):
embed = discord.Embed( embed = discord.Embed(
title="idevice Commands", title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a color=0xFA8C4A,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot) view = ideviceView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -33,9 +35,11 @@ class Idevice(commands.GroupCog, name="idevice"):
embed = discord.Embed( embed = discord.Embed(
title="idevice Commands", title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a color=0xFA8C4A,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot) view = ideviceView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -72,32 +76,29 @@ class Idevice(commands.GroupCog, name="idevice"):
async def idevice_group_mountddi(self, context: Context): async def idevice_group_mountddi(self, context: Context):
await self._invoke_hybrid(context, "mountddi") await self._invoke_hybrid(context, "mountddi")
@app_commands.command( @app_commands.command(name="help", description="idevice troubleshooting help")
name="help",
description="idevice troubleshooting help"
)
async def help(self, interaction: discord.Interaction): async def help(self, interaction: discord.Interaction):
embed = discord.Embed( embed = discord.Embed(
title="idevice Commands", title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a color=0xFA8C4A,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot) view = ideviceView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True) await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="errorcodes", name="errorcodes", description="Look up error codes and their meanings."
description="Look up error codes and their meanings."
) )
async def errorcodes(self, context, *, error_code: str = None): async def errorcodes(self, context, *, error_code: str = None):
return await errorcodes_command()(self, context, error_code=error_code) return await errorcodes_command()(self, context, error_code=error_code)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="developermode", name="developermode", description="How to turn on developer mode"
description="How to turn on developer mode"
) )
async def developermode(self, context): async def developermode(self, context):
return await developermode_command()(self, context) return await developermode_command()(self, context)
@@ -105,19 +106,17 @@ class Idevice(commands.GroupCog, name="idevice"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="noapps", name="noapps",
description="Help when apps aren't showing in installed apps view" description="Help when apps aren't showing in installed apps view",
) )
async def noapps(self, context): async def noapps(self, context):
return await noapps_command()(self, context) return await noapps_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="mountddi", description="How to manually mount DDI")
name="mountddi",
description="How to manually mount DDI"
)
async def mountddi(self, context): async def mountddi(self, context):
return await mountddi_command()(self, context) return await mountddi_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Idevice(bot) cog = Idevice(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -11,27 +11,31 @@ def developermode_command():
) )
async def developermode(self, context): async def developermode(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0xfa8c4a, color=0xFA8C4A,
description=( description=(
'# How to Enable Developer Mode\n\n---\n\n' + "# How to Enable Developer Mode\n\n---\n\n"
'1. Open the "Settings" app\n' + + '1. Open the "Settings" app\n'
'2. Navigate to "Privacy & Security"\n' + + '2. Navigate to "Privacy & Security"\n'
'3. Scroll all the way down to find "Developer Mode"\n\n' + + '3. Scroll all the way down to find "Developer Mode"\n\n'
'If you don\'t see the Developer Mode option, you need to install a developer app first.\n\n' + + "If you don't see the Developer Mode option, you need to install a developer app first.\n\n"
'You can use [SideStore](https://sidestore.io/) for this purpose - follow their installation guide to get started.' + "You can use [SideStore](https://sidestore.io/) for this purpose - follow their installation guide to get started."
) ),
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png") embed.set_author(
embed.set_footer(text=f'Last Edited by neoarz') name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
)
embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/developermode.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/developermode.py",
)) emoji="<:githubicon:1417717356846776340>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)

View File

@@ -7,13 +7,15 @@ from discord.ext.commands import Context
def errorcodes_command(): def errorcodes_command():
@commands.hybrid_command(name="errorcodes", description="Look up an idevice error code by name or number") @commands.hybrid_command(
name="errorcodes", description="Look up an idevice error code by name or number"
)
@app_commands.describe(name="Start typing to search all error names and codes") @app_commands.describe(name="Start typing to search all error names and codes")
async def errorcodes(self, context, name: str): async def errorcodes(self, context, name: str):
def load_errors(): def load_errors():
json_path = os.path.join(os.path.dirname(__file__), 'files/errorcodes.json') json_path = os.path.join(os.path.dirname(__file__), "files/errorcodes.json")
try: try:
with open(json_path, 'r', encoding='utf-8') as f: with open(json_path, "r", encoding="utf-8") as f:
return json.load(f) return json.load(f)
except FileNotFoundError: except FileNotFoundError:
self.bot.logger.error(f"Error codes JSON file not found: {json_path}") self.bot.logger.error(f"Error codes JSON file not found: {json_path}")
@@ -23,8 +25,10 @@ def errorcodes_command():
return [] return []
errors = load_errors() errors = load_errors()
key_to_data = {error['name']: (error['description'], error['code']) for error in errors} key_to_data = {
code_to_key = {error['code']: error['name'] for error in errors} error["name"]: (error["description"], error["code"]) for error in errors
}
code_to_key = {error["code"]: error["name"] for error in errors}
key = name key = name
if key not in key_to_data: if key not in key_to_data:
@@ -35,7 +39,9 @@ def errorcodes_command():
key = None key = None
if key is None or key not in key_to_data: if key is None or key not in key_to_data:
if context.interaction: if context.interaction:
await context.interaction.response.send_message("Error not found.", ephemeral=True) await context.interaction.response.send_message(
"Error not found.", ephemeral=True
)
else: else:
await context.send("Error not found.") await context.send("Error not found.")
return return
@@ -44,17 +50,21 @@ def errorcodes_command():
embed = discord.Embed( embed = discord.Embed(
description=f"## Error Code: {code}\n\n**Name**: `{key}`\n**Description**: {title}", description=f"## Error Code: {code}\n\n**Name**: `{key}`\n**Description**: {title}",
color=0xfa8c4a, color=0xFA8C4A,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/error_codes.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/error_codes.py",
)) emoji="<:githubicon:1417717356846776340>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
@@ -62,5 +72,3 @@ def errorcodes_command():
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return errorcodes return errorcodes

View File

@@ -9,8 +9,8 @@ import math
def load_error_codes(): def load_error_codes():
try: try:
json_path = os.path.join(os.path.dirname(__file__), 'files/errorcodes.json') json_path = os.path.join(os.path.dirname(__file__), "files/errorcodes.json")
with open(json_path, 'r', encoding='utf-8') as f: with open(json_path, "r", encoding="utf-8") as f:
return json.load(f) return json.load(f)
except FileNotFoundError: except FileNotFoundError:
return [] return []
@@ -24,7 +24,9 @@ class ErrorCodesBrowserView(discord.ui.View):
self.error_codes = load_error_codes() self.error_codes = load_error_codes()
self.items_per_page = items_per_page self.items_per_page = items_per_page
self.current_page = 0 self.current_page = 0
self.max_pages = math.ceil(len(self.error_codes) / items_per_page) if self.error_codes else 1 self.max_pages = (
math.ceil(len(self.error_codes) / items_per_page) if self.error_codes else 1
)
self.update_buttons() self.update_buttons()
def update_buttons(self): def update_buttons(self):
@@ -33,7 +35,7 @@ class ErrorCodesBrowserView(discord.ui.View):
first_button = discord.ui.Button( first_button = discord.ui.Button(
emoji="<:leftmax:1420240325770870905>", emoji="<:leftmax:1420240325770870905>",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
disabled=(self.current_page == 0) disabled=(self.current_page == 0),
) )
first_button.callback = self.first_page first_button.callback = self.first_page
self.add_item(first_button) self.add_item(first_button)
@@ -41,14 +43,13 @@ class ErrorCodesBrowserView(discord.ui.View):
prev_button = discord.ui.Button( prev_button = discord.ui.Button(
emoji="<:left:1420240344926126090>", emoji="<:left:1420240344926126090>",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
disabled=(self.current_page == 0) disabled=(self.current_page == 0),
) )
prev_button.callback = self.prev_page prev_button.callback = self.prev_page
self.add_item(prev_button) self.add_item(prev_button)
stop_button = discord.ui.Button( stop_button = discord.ui.Button(
emoji="<:middle:1420240356087173160>", emoji="<:middle:1420240356087173160>", style=discord.ButtonStyle.secondary
style=discord.ButtonStyle.secondary
) )
stop_button.callback = self.stop_interaction stop_button.callback = self.stop_interaction
self.add_item(stop_button) self.add_item(stop_button)
@@ -56,7 +57,7 @@ class ErrorCodesBrowserView(discord.ui.View):
next_button = discord.ui.Button( next_button = discord.ui.Button(
emoji="<:right:1420240334100627456>", emoji="<:right:1420240334100627456>",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
disabled=(self.current_page >= self.max_pages - 1) disabled=(self.current_page >= self.max_pages - 1),
) )
next_button.callback = self.next_page next_button.callback = self.next_page
self.add_item(next_button) self.add_item(next_button)
@@ -64,7 +65,7 @@ class ErrorCodesBrowserView(discord.ui.View):
last_button = discord.ui.Button( last_button = discord.ui.Button(
emoji="<:rightmax:1420240368846372886>", emoji="<:rightmax:1420240368846372886>",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
disabled=(self.current_page >= self.max_pages - 1) disabled=(self.current_page >= self.max_pages - 1),
) )
last_button.callback = self.last_page last_button.callback = self.last_page
self.add_item(last_button) self.add_item(last_button)
@@ -72,19 +73,18 @@ class ErrorCodesBrowserView(discord.ui.View):
def create_embed(self): def create_embed(self):
if not self.error_codes: if not self.error_codes:
embed = discord.Embed( embed = discord.Embed(
title="Error Codes", title="Error Codes", description="No error codes found.", color=0xFA8C4A
description="No error codes found.", )
color=0xfa8c4a embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
embed.set_footer(text="Page 0 of 0") embed.set_footer(text="Page 0 of 0")
return embed return embed
embed = discord.Embed( embed = discord.Embed(title="Error Codes", color=0xFA8C4A)
title="Error Codes", embed.set_author(
color=0xfa8c4a name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
start_idx = self.current_page * self.items_per_page start_idx = self.current_page * self.items_per_page
end_idx = min(start_idx + self.items_per_page, len(self.error_codes)) end_idx = min(start_idx + self.items_per_page, len(self.error_codes))
@@ -92,12 +92,7 @@ class ErrorCodesBrowserView(discord.ui.View):
for i, error in enumerate(current_codes): for i, error in enumerate(current_codes):
field_value = f"**Code:** `{error.get('code', 'N/A')}`\n**Name:** `{error.get('name', 'Unknown')}`\n**Description:** {error.get('description', 'No description')}" field_value = f"**Code:** `{error.get('code', 'N/A')}`\n**Name:** `{error.get('name', 'Unknown')}`\n**Description:** {error.get('description', 'No description')}"
embed.add_field( embed.add_field(name="\u200b", value=field_value, inline=True)
name="\u200b",
value=field_value,
inline=True
)
while len(current_codes) % 3 != 0: while len(current_codes) % 3 != 0:
embed.add_field(name="\u200b", value="\u200b", inline=True) embed.add_field(name="\u200b", value="\u200b", inline=True)
@@ -178,39 +173,51 @@ class ideviceSelect(discord.ui.Select):
success_embed = discord.Embed( success_embed = discord.Embed(
title="Command Executed", title="Command Executed",
description="Successfully executed `/errorcodes`. Please run /[errorcode_name] to get more information about an error code, and send it in chat", description="Successfully executed `/errorcodes`. Please run /[errorcode_name] to get more information about an error code, and send it in chat",
color=0x00FF00 color=0x00FF00,
)
success_embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
success_embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
await interaction.response.edit_message(embed=success_embed, view=None) await interaction.response.edit_message(embed=success_embed, view=None)
await interaction.followup.send(embed=embed, view=view, ephemeral=True) await interaction.followup.send(embed=embed, view=view, ephemeral=True)
except discord.Forbidden: except discord.Forbidden:
guild_info = f"server {interaction.guild.name} (ID: {interaction.guild.id})" if interaction.guild else "DM or private channel" guild_info = (
self.bot.logger.warning(f"Bot missing permissions in {guild_info} - cannot execute errorcodes command") f"server {interaction.guild.name} (ID: {interaction.guild.id})"
if interaction.guild
else "DM or private channel"
)
self.bot.logger.warning(
f"Bot missing permissions in {guild_info} - cannot execute errorcodes command"
)
if interaction.guild is None: if interaction.guild is None:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="This command cannot be executed in DMs.", description="This command cannot be executed in DMs.",
color=0xFF0000 color=0xFF0000,
) )
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Permission Error", title="Permission Error",
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xFF0000 color=0xFF0000,
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png") embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
)
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except Exception as e: except Exception as e:
self.bot.logger.error(f"Error executing errorcodes command: {e}") self.bot.logger.error(f"Error executing errorcodes command: {e}")
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="An error occurred while executing the command.", description="An error occurred while executing the command.",
color=0xFF0000 color=0xFF0000,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
return return
@@ -224,44 +231,57 @@ class ideviceSelect(discord.ui.Select):
embed = discord.Embed( embed = discord.Embed(
title="Command Executed", title="Command Executed",
description=f"Successfully executed `/{command_name}`", description=f"Successfully executed `/{command_name}`",
color=0x00FF00 color=0x00FF00,
)
embed.set_author(
name="idevice",
icon_url="https://yes.nighty.works/raw/snLMuO.png",
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except discord.Forbidden: except discord.Forbidden:
guild_info = f"server {interaction.guild.name} (ID: {interaction.guild.id})" if interaction.guild else "DM or private channel" guild_info = (
self.bot.logger.warning(f"Bot missing permissions in {guild_info} - cannot execute {command_name} command") f"server {interaction.guild.name} (ID: {interaction.guild.id})"
if interaction.guild
else "DM or private channel"
)
self.bot.logger.warning(
f"Bot missing permissions in {guild_info} - cannot execute {command_name} command"
)
if interaction.guild is None: if interaction.guild is None:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="This command cannot be executed in DMs.", description="This command cannot be executed in DMs.",
color=0xFF0000 color=0xFF0000,
) )
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Permission Error", title="Permission Error",
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xFF0000 color=0xFF0000,
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png") embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
)
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except Exception as e: except Exception as e:
self.bot.logger.error(f"Error executing {command_name} command: {e}") self.bot.logger.error(f"Error executing {command_name} command: {e}")
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="An error occurred while executing the command.", description="An error occurred while executing the command.",
color=0xFF0000 color=0xFF0000,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error", description="Command not found!", color=0xFF0000
description="Command not found!", )
color=0xFF0000 embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
@@ -282,10 +302,14 @@ def idevice_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png") embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -296,10 +320,14 @@ def idevice_command():
description="The bot needs send messages permissions in this channel.", description="The bot needs send messages permissions in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png") embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -307,14 +335,18 @@ def idevice_command():
embed = discord.Embed( embed = discord.Embed(
title="idevice Commands", title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a color=0xFA8C4A,
)
embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot) view = ideviceView(self.bot)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view, ephemeral=True) await context.interaction.response.send_message(
embed=embed, view=view, ephemeral=True
)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)

View File

@@ -5,46 +5,48 @@ import os
def mountddi_command(): def mountddi_command():
@commands.hybrid_command( @commands.hybrid_command(name="mountddi", description="How to manually mount DDI")
name="mountddi",
description="How to manually mount DDI"
)
async def mountddi(self, context): async def mountddi(self, context):
await context.defer() await context.defer()
embed = discord.Embed( embed = discord.Embed(
color=0xfa8c4a, color=0xFA8C4A,
description=( description=(
'# How to Manually Mount DDI\n\n---\n\n' "# How to Manually Mount DDI\n\n---\n\n"
'1. **Download the DDI.zip file attached above:**\n' "1. **Download the DDI.zip file attached above:**\n"
' - Save it to your device and extract the contents\n\n' " - Save it to your device and extract the contents\n\n"
'2. **Replace the DDI folder in StikDebug:**\n' "2. **Replace the DDI folder in StikDebug:**\n"
' - Navigate to the StikDebug default directory on your iPhone/iPad\n' " - Navigate to the StikDebug default directory on your iPhone/iPad\n"
' - Delete the existing DDI folder completely\n' " - Delete the existing DDI folder completely\n"
' - Replace it with the DDI folder from the downloaded zip\n' " - Replace it with the DDI folder from the downloaded zip\n"
' - Make sure it\'s in the StikDebug default directory\n\n' " - Make sure it's in the StikDebug default directory\n\n"
'3. **Restart and retry:**\n' "3. **Restart and retry:**\n"
' - Completely restart StikDebug\n' " - Completely restart StikDebug\n"
' - See if you get the same error again\n\n' " - See if you get the same error again\n\n"
) ),
) )
embed.set_author( embed.set_author(
name="idevice", name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_footer(text="Last Edited by neoarz") embed.set_footer(text="Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/mountddi.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/mountddi.py",
)) emoji="<:githubicon:1417717356846776340>",
)
)
ddi_file_path = os.path.join(os.path.dirname(__file__), 'files/DDI.zip') ddi_file_path = os.path.join(os.path.dirname(__file__), "files/DDI.zip")
file = discord.File(ddi_file_path, filename='DDI.zip') if os.path.exists(ddi_file_path) else None file = (
discord.File(ddi_file_path, filename="DDI.zip")
if os.path.exists(ddi_file_path)
else None
)
if file: if file:
await context.send(embed=embed, view=view, file=file) await context.send(embed=embed, view=view, file=file)

View File

@@ -7,32 +7,37 @@ import time
def noapps_command(): def noapps_command():
@commands.hybrid_command( @commands.hybrid_command(
name="noapps", description="Help when apps aren't showing in installed apps view" name="noapps",
description="Help when apps aren't showing in installed apps view",
) )
async def noapps(self, context): async def noapps(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0xfa8c4a, color=0xFA8C4A,
description=( description=(
'# Apps Not Showing in Installed Apps View\n\n---\n\n' + "# Apps Not Showing in Installed Apps View\n\n---\n\n"
'If apps aren\'t appearing in the StikDebug installed apps view, this is likely because they were signed with a distribution certificate instead of a development certificate.\n\n' + + "If apps aren't appearing in the StikDebug installed apps view, this is likely because they were signed with a distribution certificate instead of a development certificate.\n\n"
'Distribution certificates lack the `get-task-allow` entitlement needed for JIT.\n\n' + + "Distribution certificates lack the `get-task-allow` entitlement needed for JIT.\n\n"
'To fix this issue:\n' + + "To fix this issue:\n"
'- Use a development certificate when signing apps, or\n' + + "- Use a development certificate when signing apps, or\n"
'- Try SideStore, the best free sideloading method available\n\n' + + "- Try SideStore, the best free sideloading method available\n\n"
'More details can be found at [SideStore\'s official website](https://sidestore.io/)' + "More details can be found at [SideStore's official website](https://sidestore.io/)"
) ),
) )
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png") embed.set_author(
embed.set_footer(text=f'Last Edited by neoarz') name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
)
embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/noapps.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/idevice/noapps.py",
)) emoji="<:githubicon:1417717356846776340>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)

View File

@@ -35,11 +35,19 @@ class Media(commands.GroupCog, name="media"):
if message.author.bot: if message.author.bot:
return return
if self.bot.user in message.mentions and message.reference and message.reference.message_id: if (
self.bot.user in message.mentions
and message.reference
and message.reference.message_id
):
content = message.content.lower() content = message.content.lower()
content_without_mention = content.replace(f'<@{self.bot.user.id}>', '').replace(f'<@!{self.bot.user.id}>', '').strip() content_without_mention = (
content.replace(f"<@{self.bot.user.id}>", "")
.replace(f"<@!{self.bot.user.id}>", "")
.strip()
)
if content_without_mention.strip() == 'tweety': if content_without_mention.strip() == "tweety":
ctx = await self.bot.get_context(message) ctx = await self.bot.get_context(message)
await self.tweety(ctx) await self.tweety(ctx)
@@ -48,27 +56,33 @@ class Media(commands.GroupCog, name="media"):
embed = discord.Embed( embed = discord.Embed(
title="Media Commands", title="Media Commands",
description="Use `.media <subcommand>` or `/media <subcommand>`.", description="Use `.media <subcommand>` or `/media <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
embed.add_field(
name="Available",
value="download, mcquote, img2gif, tweety, tts",
inline=False,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
embed.add_field(name="Available", value="download, mcquote, img2gif, tweety, tts", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, *args, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, *args, **kwargs):
if name == "download": if name == "download":
await self.download(context, url=kwargs.get('url', '')) await self.download(context, url=kwargs.get("url", ""))
return return
if name == "mcquote": if name == "mcquote":
await self.mcquote(context, text=kwargs.get('text', '')) await self.mcquote(context, text=kwargs.get("text", ""))
return return
if name == "img2gif": if name == "img2gif":
await self.img2gif(context, attachment=kwargs.get('attachment')) await self.img2gif(context, attachment=kwargs.get("attachment"))
return return
if name == "tweety": if name == "tweety":
await self.tweety(context) await self.tweety(context)
return return
if name == "tts": if name == "tts":
await self.tts(context, text=kwargs.get('text')) await self.tts(context, text=kwargs.get("text"))
return return
await context.send(f"Unknown media command: {name}") await context.send(f"Unknown media command: {name}")
@@ -81,7 +95,9 @@ class Media(commands.GroupCog, name="media"):
await self._invoke_hybrid(context, "mcquote", text=text) await self._invoke_hybrid(context, "mcquote", text=text)
@media_group.command(name="img2gif") @media_group.command(name="img2gif")
async def media_group_img2gif(self, context: Context, attachment: Optional[discord.Attachment] = None): async def media_group_img2gif(
self, context: Context, attachment: Optional[discord.Attachment] = None
):
await self._invoke_hybrid(context, "img2gif", attachment=attachment) await self._invoke_hybrid(context, "img2gif", attachment=attachment)
@media_group.command(name="tweety") @media_group.command(name="tweety")
@@ -132,6 +148,7 @@ class Media(commands.GroupCog, name="media"):
async def tts(self, context, text: str = None): async def tts(self, context, text: str = None):
return await tts_command()(context, text=text) return await tts_command()(context, text=text)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Media(bot) cog = Media(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -10,6 +10,7 @@ import logging
logger = logging.getLogger("discord_bot") logger = logging.getLogger("discord_bot")
def download_command(): def download_command():
@commands.hybrid_command( @commands.hybrid_command(
name="download", name="download",
@@ -23,7 +24,9 @@ def download_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -41,7 +44,9 @@ def download_command():
description="The bot needs the `send messages` permission in this channel.", description="The bot needs the `send messages` permission in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -59,7 +64,9 @@ def download_command():
description="Please provide a valid URL to download.", description="Please provide a valid URL to download.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -74,7 +81,9 @@ def download_command():
# Check if bot has send messages permission before starting download # Check if bot has send messages permission before starting download
try: try:
test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA) test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA)
test_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") test_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.channel.send(embed=test_embed, delete_after=0.1) await context.channel.send(embed=test_embed, delete_after=0.1)
except discord.Forbidden: except discord.Forbidden:
embed = discord.Embed( embed = discord.Embed(
@@ -82,7 +91,9 @@ def download_command():
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -102,12 +113,16 @@ def download_command():
description="Please provide a valid URL.", description="Please provide a valid URL.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if not interaction.response.is_done(): if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True) await interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await interaction.followup.send(embed=embed, ephemeral=True) await interaction.followup.send(embed=embed, ephemeral=True)
else: else:
@@ -119,7 +134,9 @@ def download_command():
description="Please provide a valid URL.", description="Please provide a valid URL.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -136,12 +153,16 @@ def download_command():
description="<a:mariospin:1423677027013103709> Downloading video... This may take a moment.", description="<a:mariospin:1423677027013103709> Downloading video... This may take a moment.",
color=0x7289DA, color=0x7289DA,
) )
processing_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") processing_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if not interaction.response.is_done(): if not interaction.response.is_done():
await interaction.response.send_message(embed=processing_embed, ephemeral=True) await interaction.response.send_message(
embed=processing_embed, ephemeral=True
)
else: else:
await interaction.followup.send(embed=processing_embed, ephemeral=True) await interaction.followup.send(embed=processing_embed, ephemeral=True)
else: else:
@@ -150,21 +171,23 @@ def download_command():
temp_dir = tempfile.mkdtemp() temp_dir = tempfile.mkdtemp()
# Try Docker path first, fallback to local path for development # Try Docker path first, fallback to local path for development
cookie_path = '/bot/cogs/media/files/cookies.txt' cookie_path = "/bot/cogs/media/files/cookies.txt"
if not os.path.exists(cookie_path): if not os.path.exists(cookie_path):
cookie_path = os.path.join(os.path.dirname(__file__), 'files', 'cookies.txt') cookie_path = os.path.join(
os.path.dirname(__file__), "files", "cookies.txt"
)
ydl_opts = { ydl_opts = {
'format': 'bestvideo[filesize<200M]+bestaudio[filesize<200M]/best[filesize<200M]/bestvideo+bestaudio/best', "format": "bestvideo[filesize<200M]+bestaudio[filesize<200M]/best[filesize<200M]/bestvideo+bestaudio/best",
'outtmpl': os.path.join(temp_dir, '%(title)s.%(ext)s'), "outtmpl": os.path.join(temp_dir, "%(title)s.%(ext)s"),
'noplaylist': True, "noplaylist": True,
'extract_flat': False, "extract_flat": False,
'writesubtitles': False, "writesubtitles": False,
'writeautomaticsub': False, "writeautomaticsub": False,
'writethumbnail': False, "writethumbnail": False,
'ignoreerrors': False, "ignoreerrors": False,
'merge_output_format': 'mp4', "merge_output_format": "mp4",
'cookiefile': cookie_path, "cookiefile": cookie_path,
} }
try: try:
@@ -176,59 +199,99 @@ def download_command():
if not info: if not info:
raise Exception("Could not extract video information") raise Exception("Could not extract video information")
video_title = info.get('title', 'Unknown Title') video_title = info.get("title", "Unknown Title")
video_duration_seconds = int(info.get('duration') or 0) video_duration_seconds = int(info.get("duration") or 0)
video_uploader = info.get('uploader', 'Unknown') video_uploader = info.get("uploader", "Unknown")
video_url = info.get('webpage_url') or info.get('original_url') or url video_url = info.get("webpage_url") or info.get("original_url") or url
platform = info.get('extractor') or info.get('extractor_key') or 'Unknown' platform = (
view_count = info.get('view_count') info.get("extractor") or info.get("extractor_key") or "Unknown"
)
view_count = info.get("view_count")
files = [f for f in os.listdir(temp_dir) if os.path.isfile(os.path.join(temp_dir, f))] files = [
f
for f in os.listdir(temp_dir)
if os.path.isfile(os.path.join(temp_dir, f))
]
if not files: if not files:
raise Exception("No video file was downloaded") raise Exception("No video file was downloaded")
video_file = os.path.join(temp_dir, files[0]) video_file = os.path.join(temp_dir, files[0])
file_size = os.path.getsize(video_file) file_size = os.path.getsize(video_file)
logger.info(f"File size: {file_size} bytes ({file_size / (1024*1024):.2f} MB)") logger.info(
f"File size: {file_size} bytes ({file_size / (1024 * 1024):.2f} MB)"
)
if file_size > 24 * 1024 * 1024: # 24MB limit if file_size > 24 * 1024 * 1024: # 24MB limit
logger.info("File is over 24MB, uploading to Catbox") logger.info("File is over 24MB, uploading to Catbox")
async def upload_to_catbox(path: str) -> str: async def upload_to_catbox(path: str) -> str:
try: try:
file_size_bytes = os.path.getsize(path) file_size_bytes = os.path.getsize(path)
except Exception: except Exception:
file_size_bytes = -1 file_size_bytes = -1
logger.info(f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}") logger.info(
f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}"
)
form = aiohttp.FormData() form = aiohttp.FormData()
form.add_field('reqtype', 'fileupload') form.add_field("reqtype", "fileupload")
form.add_field('fileToUpload', open(path, 'rb'), filename=os.path.basename(path)) form.add_field(
"fileToUpload",
open(path, "rb"),
filename=os.path.basename(path),
)
timeout = aiohttp.ClientTimeout(total=600) timeout = aiohttp.ClientTimeout(total=600)
async with aiohttp.ClientSession(timeout=timeout) as session: async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.post('https://catbox.moe/user/api.php', data=form) as resp: async with session.post(
"https://catbox.moe/user/api.php", data=form
) as resp:
text = await resp.text() text = await resp.text()
logger.info(f"Catbox response: status={resp.status} body_len={len(text)}") logger.info(
if resp.status == 200 and text.startswith('https://'): f"Catbox response: status={resp.status} body_len={len(text)}"
)
if resp.status == 200 and text.startswith("https://"):
url_text = text.strip() url_text = text.strip()
logger.info(f"Catbox upload success: url={url_text}") logger.info(
f"Catbox upload success: url={url_text}"
)
return url_text return url_text
logger.error(f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}") logger.error(
f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}"
)
raise RuntimeError(f"Upload failed: {text.strip()}") raise RuntimeError(f"Upload failed: {text.strip()}")
try: try:
link = await upload_to_catbox(video_file) link = await upload_to_catbox(video_file)
minutes, seconds = divmod(video_duration_seconds, 60) minutes, seconds = divmod(video_duration_seconds, 60)
duration_str = f"{minutes}:{seconds:02d}" duration_str = f"{minutes}:{seconds:02d}"
description_text = f"### **[{video_title}]({video_url})**" if video_url else f"### **{video_title}**" description_text = (
f"### **[{video_title}]({video_url})**"
if video_url
else f"### **{video_title}**"
)
embed = discord.Embed( embed = discord.Embed(
title="Download", title="Download",
description=description_text, description=description_text,
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
embed.add_field(name="Uploader", value=video_uploader or "Unknown", inline=True) name="Media",
embed.add_field(name="Duration", value=duration_str, inline=True) icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
embed.add_field(
name="Uploader",
value=video_uploader or "Unknown",
inline=True,
)
embed.add_field(
name="Duration", value=duration_str, inline=True
)
embed.add_field(name="Platform", value=platform, inline=True) embed.add_field(name="Platform", value=platform, inline=True)
embed.set_footer(text=f"Requested by {context.author.name}", icon_url=context.author.display_avatar.url) embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
if interaction is not None: if interaction is not None:
await context.channel.send(embed=embed) await context.channel.send(embed=embed)
@@ -255,7 +318,10 @@ def download_command():
description=description, description=description,
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
if interaction is not None: if interaction is not None:
try: try:
@@ -271,20 +337,32 @@ def download_command():
logger.info("File is under 24MB, sending directly to Discord") logger.info("File is under 24MB, sending directly to Discord")
minutes, seconds = divmod(video_duration_seconds, 60) minutes, seconds = divmod(video_duration_seconds, 60)
duration_str = f"{minutes}:{seconds:02d}" duration_str = f"{minutes}:{seconds:02d}"
description_text = f"### **[{video_title}]({video_url})**" if video_url else f"### **{video_title}**" description_text = (
f"### **[{video_title}]({video_url})**"
if video_url
else f"### **{video_title}**"
)
embed = discord.Embed( embed = discord.Embed(
title="Download", title="Download",
description=description_text, description=description_text,
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
embed.add_field(name="Uploader", value=video_uploader or "Unknown", inline=True) name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
embed.add_field(
name="Uploader", value=video_uploader or "Unknown", inline=True
)
embed.add_field(name="Duration", value=duration_str, inline=True) embed.add_field(name="Duration", value=duration_str, inline=True)
embed.add_field(name="Platform", value=platform, inline=True) embed.add_field(name="Platform", value=platform, inline=True)
embed.set_footer(text=f"Requested by {context.author.name}", icon_url=context.author.display_avatar.url) embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
try: try:
with open(video_file, 'rb') as f: with open(video_file, "rb") as f:
file = discord.File(f, filename=files[0]) file = discord.File(f, filename=files[0])
if interaction is not None: if interaction is not None:
@@ -300,40 +378,82 @@ def download_command():
await context.channel.send(file=file) await context.channel.send(file=file)
except discord.HTTPException as e: except discord.HTTPException as e:
if e.status == 413: if e.status == 413:
logger.info("Discord rejected file (413), falling back to Catbox upload") logger.info(
"Discord rejected file (413), falling back to Catbox upload"
)
async def upload_to_catbox(path: str) -> str: async def upload_to_catbox(path: str) -> str:
try: try:
file_size_bytes = os.path.getsize(path) file_size_bytes = os.path.getsize(path)
except Exception: except Exception:
file_size_bytes = -1 file_size_bytes = -1
logger.info(f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}") logger.info(
f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}"
)
form = aiohttp.FormData() form = aiohttp.FormData()
form.add_field('reqtype', 'fileupload') form.add_field("reqtype", "fileupload")
form.add_field('fileToUpload', open(path, 'rb'), filename=os.path.basename(path)) form.add_field(
"fileToUpload",
open(path, "rb"),
filename=os.path.basename(path),
)
timeout = aiohttp.ClientTimeout(total=600) timeout = aiohttp.ClientTimeout(total=600)
async with aiohttp.ClientSession(timeout=timeout) as session: async with aiohttp.ClientSession(
async with session.post('https://catbox.moe/user/api.php', data=form) as resp: timeout=timeout
) as session:
async with session.post(
"https://catbox.moe/user/api.php", data=form
) as resp:
text = await resp.text() text = await resp.text()
logger.info(f"Catbox response: status={resp.status} body_len={len(text)}") logger.info(
if resp.status == 200 and text.startswith('https://'): f"Catbox response: status={resp.status} body_len={len(text)}"
)
if resp.status == 200 and text.startswith(
"https://"
):
url_text = text.strip() url_text = text.strip()
logger.info(f"Catbox upload success: url={url_text}") logger.info(
f"Catbox upload success: url={url_text}"
)
return url_text return url_text
logger.error(f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}") logger.error(
raise RuntimeError(f"Upload failed: {text.strip()}") f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}"
)
raise RuntimeError(
f"Upload failed: {text.strip()}"
)
try: try:
link = await upload_to_catbox(video_file) link = await upload_to_catbox(video_file)
description_text_with_link = f"### **[{video_title}]({video_url})**\n\n{link}" if video_url else f"### **{video_title}**\n\n{link}" description_text_with_link = (
f"### **[{video_title}]({video_url})**\n\n{link}"
if video_url
else f"### **{video_title}**\n\n{link}"
)
embed = discord.Embed( embed = discord.Embed(
title="Download", title="Download",
description=description_text, description=description_text,
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
embed.add_field(name="Uploader", value=video_uploader or "Unknown", inline=True) name="Media",
embed.add_field(name="Duration", value=duration_str, inline=True) icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
embed.add_field(name="Platform", value=platform, inline=True) )
embed.set_footer(text=f"Requested by {context.author.name}", icon_url=context.author.display_avatar.url) embed.add_field(
name="Uploader",
value=video_uploader or "Unknown",
inline=True,
)
embed.add_field(
name="Duration", value=duration_str, inline=True
)
embed.add_field(
name="Platform", value=platform, inline=True
)
embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
if interaction is not None: if interaction is not None:
await context.channel.send(embed=embed) await context.channel.send(embed=embed)
@@ -347,20 +467,27 @@ def download_command():
await context.channel.send(embed=embed) await context.channel.send(embed=embed)
await context.channel.send(link) await context.channel.send(link)
except Exception as upload_error: except Exception as upload_error:
logger.exception(f"Catbox upload exception: {upload_error}") logger.exception(
f"Catbox upload exception: {upload_error}"
)
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description=f"Discord rejected the file and Catbox upload failed: {upload_error}", description=f"Discord rejected the file and Catbox upload failed: {upload_error}",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
if interaction is not None: if interaction is not None:
try: try:
await interaction.delete_original_response() await interaction.delete_original_response()
except: except:
pass pass
await interaction.followup.send(embed=embed, ephemeral=True) await interaction.followup.send(
embed=embed, ephemeral=True
)
else: else:
await processing_msg.delete() await processing_msg.delete()
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
@@ -373,7 +500,9 @@ def download_command():
description=f"Failed to download video: {str(e)}", description=f"Failed to download video: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
if interaction is not None: if interaction is not None:
try: try:

View File

@@ -6,8 +6,10 @@ from PIL import Image
import subprocess import subprocess
import shutil import shutil
from typing import Optional from typing import Optional
try: try:
import pillow_heif import pillow_heif
pillow_heif.register_heif_opener() pillow_heif.register_heif_opener()
except Exception: except Exception:
pass pass
@@ -30,6 +32,7 @@ async def send_error_message(context, description: str):
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
def img2gif_command(): def img2gif_command():
@commands.hybrid_command( @commands.hybrid_command(
name="img2gif", name="img2gif",
@@ -39,14 +42,30 @@ def img2gif_command():
async def img2gif(self, context, attachment: Optional[discord.Attachment] = None): async def img2gif(self, context, attachment: Optional[discord.Attachment] = None):
resolved_attachment = attachment resolved_attachment = attachment
if resolved_attachment is None: if resolved_attachment is None:
if context.message and context.message.reference and context.message.reference.resolved: if (
context.message
and context.message.reference
and context.message.reference.resolved
):
ref_msg = context.message.reference.resolved ref_msg = context.message.reference.resolved
if isinstance(ref_msg, discord.Message) and ref_msg.attachments: if isinstance(ref_msg, discord.Message) and ref_msg.attachments:
resolved_attachment = ref_msg.attachments[0] resolved_attachment = ref_msg.attachments[0]
if resolved_attachment is None and context.message and context.message.attachments: if (
resolved_attachment is None
and context.message
and context.message.attachments
):
resolved_attachment = context.message.attachments[0] resolved_attachment = context.message.attachments[0]
if resolved_attachment is None or not resolved_attachment.filename.lower().endswith((".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tiff", ".heic", ".heif")): if (
await send_error_message(context, "Provide or reply to an image (png/jpg/jpeg/webp/bmp/tiff/heic/heif).") resolved_attachment is None
or not resolved_attachment.filename.lower().endswith(
(".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tiff", ".heic", ".heif")
)
):
await send_error_message(
context,
"Provide or reply to an image (png/jpg/jpeg/webp/bmp/tiff/heic/heif).",
)
return return
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
@@ -59,12 +78,16 @@ def img2gif_command():
description="<a:mariospin:1423677027013103709> Converting image...", description="<a:mariospin:1423677027013103709> Converting image...",
color=0x7289DA, color=0x7289DA,
) )
processing_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") processing_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
processing_msg = await context.send(embed=processing_embed) processing_msg = await context.send(embed=processing_embed)
tmp_dir = tempfile.mkdtemp() tmp_dir = tempfile.mkdtemp()
src_path = os.path.join(tmp_dir, resolved_attachment.filename) src_path = os.path.join(tmp_dir, resolved_attachment.filename)
out_path = os.path.join(tmp_dir, os.path.splitext(resolved_attachment.filename)[0] + ".gif") out_path = os.path.join(
tmp_dir, os.path.splitext(resolved_attachment.filename)[0] + ".gif"
)
try: try:
await resolved_attachment.save(src_path) await resolved_attachment.save(src_path)
@@ -75,20 +98,42 @@ def img2gif_command():
img = img.convert("RGBA") img = img.convert("RGBA")
duration_ms = 100 duration_ms = 100
loop = 0 loop = 0
img.save(out_path, format="GIF", save_all=True, optimize=True, duration=duration_ms, loop=loop) img.save(
out_path,
format="GIF",
save_all=True,
optimize=True,
duration=duration_ms,
loop=loop,
)
except Exception: except Exception:
if resolved_attachment.filename.lower().endswith((".heic", ".heif")) and shutil.which("ffmpeg"): if resolved_attachment.filename.lower().endswith(
png_path = os.path.join(tmp_dir, os.path.splitext(resolved_attachment.filename)[0] + ".png") (".heic", ".heif")
) and shutil.which("ffmpeg"):
png_path = os.path.join(
tmp_dir,
os.path.splitext(resolved_attachment.filename)[0] + ".png",
)
try: try:
subprocess.run([ subprocess.run(
"ffmpeg", "-y", "-i", src_path, png_path ["ffmpeg", "-y", "-i", src_path, png_path],
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
with Image.open(png_path) as img: with Image.open(png_path) as img:
if img.mode not in ("RGB", "RGBA"): if img.mode not in ("RGB", "RGBA"):
img = img.convert("RGBA") img = img.convert("RGBA")
duration_ms = 100 duration_ms = 100
loop = 0 loop = 0
img.save(out_path, format="GIF", save_all=True, optimize=True, duration=duration_ms, loop=loop) img.save(
out_path,
format="GIF",
save_all=True,
optimize=True,
duration=duration_ms,
loop=loop,
)
except Exception as conv_err: except Exception as conv_err:
raise conv_err raise conv_err
else: else:
@@ -103,18 +148,30 @@ def img2gif_command():
await context.send(file=file) await context.send(file=file)
except Exception as e: except Exception as e:
if interaction is not None: if interaction is not None:
await interaction.followup.send(embed=discord.Embed( await interaction.followup.send(
title="Error", embed=discord.Embed(
description=f"Failed to convert image: {e}", title="Error",
color=0xE02B2B, description=f"Failed to convert image: {e}",
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"), ephemeral=True) color=0xE02B2B,
).set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
),
ephemeral=True,
)
else: else:
await processing_msg.delete() await processing_msg.delete()
await context.send(embed=discord.Embed( await context.send(
title="Error", embed=discord.Embed(
description=f"Failed to convert image: {e}", title="Error",
color=0xE02B2B, description=f"Failed to convert image: {e}",
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"), ephemeral=True) color=0xE02B2B,
).set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
),
ephemeral=True,
)
finally: finally:
try: try:
for f in os.listdir(tmp_dir): for f in os.listdir(tmp_dir):
@@ -127,5 +184,3 @@ def img2gif_command():
pass pass
return img2gif return img2gif

View File

@@ -6,6 +6,7 @@ from discord.ext import commands
import aiohttp import aiohttp
import random import random
def mcquote_command(): def mcquote_command():
@commands.hybrid_command( @commands.hybrid_command(
name="mcquote", name="mcquote",
@@ -19,7 +20,9 @@ def mcquote_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -37,7 +40,9 @@ def mcquote_command():
description="The bot needs the `send messages` permission in this channel.", description="The bot needs the `send messages` permission in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -55,7 +60,9 @@ def mcquote_command():
description="Please provide text for the Minecraft quote.", description="Please provide text for the Minecraft quote.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -73,7 +80,9 @@ def mcquote_command():
description="Text must be 25 characters or less.", description="Text must be 25 characters or less.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -88,7 +97,9 @@ def mcquote_command():
# Check if bot has send messages permission before starting quote generation # Check if bot has send messages permission before starting quote generation
try: try:
test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA) test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA)
test_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") test_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.channel.send(embed=test_embed, delete_after=0.1) await context.channel.send(embed=test_embed, delete_after=0.1)
except discord.Forbidden: except discord.Forbidden:
embed = discord.Embed( embed = discord.Embed(
@@ -96,7 +107,9 @@ def mcquote_command():
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -113,12 +126,16 @@ def mcquote_command():
description="<a:mariospin:1423677027013103709> Generating quote... This may take a moment.", description="<a:mariospin:1423677027013103709> Generating quote... This may take a moment.",
color=0x7289DA, color=0x7289DA,
) )
processing_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") processing_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if not interaction.response.is_done(): if not interaction.response.is_done():
await interaction.response.send_message(embed=processing_embed, ephemeral=True) await interaction.response.send_message(
embed=processing_embed, ephemeral=True
)
else: else:
await interaction.followup.send(embed=processing_embed, ephemeral=True) await interaction.followup.send(embed=processing_embed, ephemeral=True)
else: else:
@@ -126,7 +143,7 @@ def mcquote_command():
quote_text = text.replace(" ", "+") quote_text = text.replace(" ", "+")
random_number = random.randint(1, 39) random_number = random.randint(1, 39)
mc_quote_url = f'https://skinmc.net/achievement/{random_number}/Achievement+Unlocked!/{quote_text}' mc_quote_url = f"https://skinmc.net/achievement/{random_number}/Achievement+Unlocked!/{quote_text}"
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
@@ -142,10 +159,15 @@ def mcquote_command():
title="Minecraft Quote", title="Minecraft Quote",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
embed.set_footer(text=f"Requested by {context.author.name}", icon_url=context.author.display_avatar.url) name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
with open(temp_file_path, 'rb') as f: with open(temp_file_path, "rb") as f:
file = discord.File(f, filename="mcquote.png") file = discord.File(f, filename="mcquote.png")
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
@@ -168,7 +190,9 @@ def mcquote_command():
description="Failed to generate Minecraft quote. Please try again later.", description="Failed to generate Minecraft quote. Please try again later.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -186,7 +210,9 @@ def mcquote_command():
description=f"An unexpected error occurred: {str(e)}", description=f"An unexpected error occurred: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:

View File

@@ -11,8 +11,8 @@ from gtts import gTTS
DEFAULT_LANG = "en" DEFAULT_LANG = "en"
def tts_command():
def tts_command():
async def send_embed( async def send_embed(
context: commands.Context, context: commands.Context,
embed: discord.Embed, embed: discord.Embed,
@@ -24,14 +24,20 @@ def tts_command():
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
if file: if file:
await interaction.followup.send(embed=embed, file=file, ephemeral=ephemeral) await interaction.followup.send(
embed=embed, file=file, ephemeral=ephemeral
)
else: else:
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
if file: if file:
await interaction.response.send_message(embed=embed, file=file, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, file=file, ephemeral=ephemeral
)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
if file: if file:
await context.send(embed=embed, file=file) await context.send(embed=embed, file=file)
@@ -42,8 +48,7 @@ def tts_command():
try: try:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
audio_bytes = await loop.run_in_executor( audio_bytes = await loop.run_in_executor(
None, None, lambda: _generate_tts_sync(text)
lambda: _generate_tts_sync(text)
) )
return audio_bytes, None return audio_bytes, None
except Exception as e: except Exception as e:
@@ -70,7 +75,9 @@ def tts_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -88,7 +95,9 @@ def tts_command():
description="The bot needs the `send messages` permission in this channel.", description="The bot needs the `send messages` permission in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -101,29 +110,33 @@ def tts_command():
return return
if not text or not text.strip(): if not text or not text.strip():
if context.message and context.message.reference and context.message.reference.resolved: if (
context.message
and context.message.reference
and context.message.reference.resolved
):
referenced = context.message.reference.resolved referenced = context.message.reference.resolved
if isinstance(referenced, discord.Message) and referenced.content: if isinstance(referenced, discord.Message) and referenced.content:
text = referenced.content text = referenced.content
if not text or not text.strip(): if not text or not text.strip():
embed = ( embed = discord.Embed(
discord.Embed( title="Error",
title="Error", description="Please provide text to convert or reply to a message containing text.",
description="Please provide text to convert or reply to a message containing text.", color=0xE02B2B,
color=0xE02B2B, ).set_author(
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
) )
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
text = text.strip() text = text.strip()
if len(text) > 500: if len(text) > 500:
embed = ( embed = discord.Embed(
discord.Embed( title="Error",
title="Error", description="Text is too long. Please limit to 500 characters.",
description="Text is too long. Please limit to 500 characters.", color=0xE02B2B,
color=0xE02B2B, ).set_author(
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
) )
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -131,7 +144,9 @@ def tts_command():
# Check if bot has send messages permission before starting TTS generation # Check if bot has send messages permission before starting TTS generation
try: try:
test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA) test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA)
test_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") test_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.channel.send(embed=test_embed, delete_after=0.1) await context.channel.send(embed=test_embed, delete_after=0.1)
except discord.Forbidden: except discord.Forbidden:
embed = discord.Embed( embed = discord.Embed(
@@ -139,7 +154,9 @@ def tts_command():
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -151,43 +168,45 @@ def tts_command():
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
processing_embed = ( processing_embed = discord.Embed(
discord.Embed( title="TTS (Processing)",
title="TTS (Processing)", description="<a:mariospin:1423677027013103709> Generating speech...",
description="<a:mariospin:1423677027013103709> Generating speech...", color=0x7289DA,
color=0x7289DA, ).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
processing_message = None processing_message = None
sent_initial_interaction_response = False sent_initial_interaction_response = False
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
processing_message = await interaction.followup.send(embed=processing_embed, ephemeral=True) processing_message = await interaction.followup.send(
embed=processing_embed, ephemeral=True
)
else: else:
await interaction.response.send_message(embed=processing_embed, ephemeral=True) await interaction.response.send_message(
embed=processing_embed, ephemeral=True
)
sent_initial_interaction_response = True sent_initial_interaction_response = True
if not interaction.response.is_done(): if not interaction.response.is_done():
await interaction.response.defer(ephemeral=False) await interaction.response.defer(ephemeral=False)
else: else:
processing_embed = ( processing_embed = discord.Embed(
discord.Embed( title="TTS (Processing)",
title="TTS (Processing)", description="<a:mariospin:1423677027013103709> Generating speech...",
description="<a:mariospin:1423677027013103709> Generating speech...", color=0x7289DA,
color=0x7289DA, ).set_author(
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
) )
processing_message = await context.send(embed=processing_embed) processing_message = await context.send(embed=processing_embed)
audio_bytes, error = await generate_tts_audio(text) audio_bytes, error = await generate_tts_audio(text)
if error or not audio_bytes: if error or not audio_bytes:
embed = ( embed = discord.Embed(
discord.Embed( title="Error",
title="Error", description=f"Failed to generate speech. {error or 'Unknown error.'}",
description=f"Failed to generate speech. {error or 'Unknown error.'}", color=0xE02B2B,
color=0xE02B2B, ).set_author(
).set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
) )
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
if interaction is not None and sent_initial_interaction_response: if interaction is not None and sent_initial_interaction_response:
@@ -213,7 +232,9 @@ def tts_command():
description=f"**Input:** {text}", description=f"**Input:** {text}",
color=0x7289DA, color=0x7289DA,
) )
.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") .set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
.set_footer( .set_footer(
text=f"Requested by {context.author.display_name}", text=f"Requested by {context.author.display_name}",
icon_url=getattr(context.author.display_avatar, "url", None), icon_url=getattr(context.author.display_avatar, "url", None),

View File

@@ -16,17 +16,20 @@ import asyncio
def break_long_words(text: str, max_word_length: int = 50) -> str: def break_long_words(text: str, max_word_length: int = 50) -> str:
words = text.split(' ') words = text.split(" ")
result = [] result = []
for word in words: for word in words:
if len(word) > max_word_length: if len(word) > max_word_length:
chunks = [word[i:i+max_word_length] for i in range(0, len(word), max_word_length)] chunks = [
result.append(' '.join(chunks)) word[i : i + max_word_length]
for i in range(0, len(word), max_word_length)
]
result.append(" ".join(chunks))
else: else:
result.append(word) result.append(word)
return ' '.join(result) return " ".join(result)
class TweetyHelpView(discord.ui.View): class TweetyHelpView(discord.ui.View):
@@ -43,17 +46,25 @@ class TweetyHelpView(discord.ui.View):
"description": "Use the prefix command `.media tweety` while replying to a message.", "description": "Use the prefix command `.media tweety` while replying to a message.",
"gif_url": "https://yes.nighty.works/raw/VrKX1L.gif", "gif_url": "https://yes.nighty.works/raw/VrKX1L.gif",
"fields": [ "fields": [
{"name": "How to use", "value": "1. Reply to any message\n2. Type `.media tweety`\n3. Use the buttons to customize!", "inline": False}, {
] "name": "How to use",
"value": "1. Reply to any message\n2. Type `.media tweety`\n3. Use the buttons to customize!",
"inline": False,
},
],
}, },
{ {
"title": "Tweety (Method 2)", "title": "Tweety (Method 2)",
"description": f"Mention <@{bot.user.id}> with `tweety` while replying to a message.", "description": f"Mention <@{bot.user.id}> with `tweety` while replying to a message.",
"gif_url": "https://yes.nighty.works/raw/9XEe9j.gif", "gif_url": "https://yes.nighty.works/raw/9XEe9j.gif",
"fields": [ "fields": [
{"name": "How to use", "value": f"1. Reply to any message\n2. Type `<@{bot.user.id}> tweety`\n3. Use the buttons to customize!", "inline": False}, {
] "name": "How to use",
} "value": f"1. Reply to any message\n2. Type `<@{bot.user.id}> tweety`\n3. Use the buttons to customize!",
"inline": False,
},
],
},
] ]
self.update_buttons() self.update_buttons()
@@ -64,10 +75,14 @@ class TweetyHelpView(discord.ui.View):
description=page["description"], description=page["description"],
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
for field in page["fields"]: for field in page["fields"]:
embed.add_field(name=field["name"], value=field["value"], inline=field["inline"]) embed.add_field(
name=field["name"], value=field["value"], inline=field["inline"]
)
embed.set_image(url=page["gif_url"]) embed.set_image(url=page["gif_url"])
embed.set_footer(text=f"Page {self.current_page + 1}/{len(self.pages)}") embed.set_footer(text=f"Page {self.current_page + 1}/{len(self.pages)}")
@@ -81,7 +96,7 @@ class TweetyHelpView(discord.ui.View):
label="Prev", label="Prev",
style=discord.ButtonStyle.secondary, style=discord.ButtonStyle.secondary,
emoji=discord.PartialEmoji(name="left", id=1420240344926126090), emoji=discord.PartialEmoji(name="left", id=1420240344926126090),
disabled=self.current_page == 0 disabled=self.current_page == 0,
) )
prev_button.callback = self.previous_page prev_button.callback = self.previous_page
self.add_item(prev_button) self.add_item(prev_button)
@@ -90,32 +105,40 @@ class TweetyHelpView(discord.ui.View):
label="Next", label="Next",
style=discord.ButtonStyle.secondary, style=discord.ButtonStyle.secondary,
emoji=discord.PartialEmoji(name="right", id=1420240334100627456), emoji=discord.PartialEmoji(name="right", id=1420240334100627456),
disabled=self.current_page == len(self.pages) - 1 disabled=self.current_page == len(self.pages) - 1,
) )
next_button.callback = self.next_page next_button.callback = self.next_page
self.add_item(next_button) self.add_item(next_button)
async def previous_page(self, interaction: discord.Interaction): async def previous_page(self, interaction: discord.Interaction):
if interaction.user.id != self.user_id: if interaction.user.id != self.user_id:
await interaction.response.send_message("You can't control someone else's help menu!", ephemeral=True) await interaction.response.send_message(
"You can't control someone else's help menu!", ephemeral=True
)
return return
if self.current_page > 0: if self.current_page > 0:
self.current_page -= 1 self.current_page -= 1
self.update_buttons() self.update_buttons()
await interaction.response.edit_message(embed=self.create_embed(), view=self) await interaction.response.edit_message(
embed=self.create_embed(), view=self
)
else: else:
await interaction.response.defer() await interaction.response.defer()
async def next_page(self, interaction: discord.Interaction): async def next_page(self, interaction: discord.Interaction):
if interaction.user.id != self.user_id: if interaction.user.id != self.user_id:
await interaction.response.send_message("You can't control someone else's help menu!", ephemeral=True) await interaction.response.send_message(
"You can't control someone else's help menu!", ephemeral=True
)
return return
if self.current_page < len(self.pages) - 1: if self.current_page < len(self.pages) - 1:
self.current_page += 1 self.current_page += 1
self.update_buttons() self.update_buttons()
await interaction.response.edit_message(embed=self.create_embed(), view=self) await interaction.response.edit_message(
embed=self.create_embed(), view=self
)
else: else:
await interaction.response.defer() await interaction.response.defer()
@@ -125,7 +148,14 @@ class TweetyHelpView(discord.ui.View):
class TweetyView(discord.ui.View): class TweetyView(discord.ui.View):
def __init__(self, author_id: int, original_message, tweet_data: dict, api_url: str, image_message: Optional[discord.Message] = None): def __init__(
self,
author_id: int,
original_message,
tweet_data: dict,
api_url: str,
image_message: Optional[discord.Message] = None,
):
super().__init__(timeout=300) super().__init__(timeout=300)
self.author_id = author_id self.author_id = author_id
self.original_message = original_message self.original_message = original_message
@@ -144,18 +174,24 @@ class TweetyView(discord.ui.View):
dark_button = discord.ui.Button( dark_button = discord.ui.Button(
label="Dark Mode" if self.is_dark else "Light Mode", label="Dark Mode" if self.is_dark else "Light Mode",
style=discord.ButtonStyle.primary if self.is_dark else discord.ButtonStyle.secondary, style=discord.ButtonStyle.primary
if self.is_dark
else discord.ButtonStyle.secondary,
emoji=discord.PartialEmoji(name="darkmode", id=1425165393751965884), emoji=discord.PartialEmoji(name="darkmode", id=1425165393751965884),
custom_id="toggle_dark" custom_id="toggle_dark",
) )
dark_button.callback = self.toggle_dark_callback dark_button.callback = self.toggle_dark_callback
self.add_item(dark_button) self.add_item(dark_button)
verified_button = discord.ui.Button( verified_button = discord.ui.Button(
label="Verified", label="Verified",
style=discord.ButtonStyle.primary if self.is_verified else discord.ButtonStyle.secondary, style=discord.ButtonStyle.primary
emoji=discord.PartialEmoji(name="TwitterVerifiedBadge", id=1425165432142172392), if self.is_verified
custom_id="toggle_verified" else discord.ButtonStyle.secondary,
emoji=discord.PartialEmoji(
name="TwitterVerifiedBadge", id=1425165432142172392
),
custom_id="toggle_verified",
) )
verified_button.callback = self.toggle_verified_callback verified_button.callback = self.toggle_verified_callback
self.add_item(verified_button) self.add_item(verified_button)
@@ -168,7 +204,9 @@ class TweetyView(discord.ui.View):
description="Stop spamming! You've reached the maximum number of changes for this tweet.", description="Stop spamming! You've reached the maximum number of changes for this tweet.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await interaction.response.send_message(embed=embed, ephemeral=True) await interaction.response.send_message(embed=embed, ephemeral=True)
return return
@@ -189,9 +227,8 @@ class TweetyView(discord.ui.View):
async with session.post( async with session.post(
f"{self.api_url}/api/render", f"{self.api_url}/api/render",
json=self.tweet_data, json=self.tweet_data,
headers={"Content-Type": "application/json"} headers={"Content-Type": "application/json"},
) as response: ) as response:
if response.status != 200: if response.status != 200:
error_text = await response.text() error_text = await response.text()
embed = discord.Embed( embed = discord.Embed(
@@ -199,23 +236,27 @@ class TweetyView(discord.ui.View):
description=f"API Error ({response.status}): {error_text}", description=f"API Error ({response.status}): {error_text}",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
await interaction.followup.send(embed=embed, ephemeral=True) await interaction.followup.send(embed=embed, ephemeral=True)
return return
image_data = await response.read() image_data = await response.read()
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file: with tempfile.NamedTemporaryFile(
delete=False, suffix=".png"
) as temp_file:
temp_file.write(image_data) temp_file.write(image_data)
temp_file_path = temp_file.name temp_file_path = temp_file.name
with open(temp_file_path, 'rb') as f: with open(temp_file_path, "rb") as f:
author_name = self.original_message.author.name author_name = self.original_message.author.name
filename = f"tweet_{author_name}_{int(datetime.now().timestamp())}.png" filename = (
file = discord.File( f"tweet_{author_name}_{int(datetime.now().timestamp())}.png"
f,
filename=filename
) )
file = discord.File(f, filename=filename)
self.update_button_styles() self.update_button_styles()
@@ -232,7 +273,9 @@ class TweetyView(discord.ui.View):
description="Error regenerating tweet image", description="Error regenerating tweet image",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await interaction.followup.send(embed=embed, ephemeral=True) await interaction.followup.send(embed=embed, ephemeral=True)
async def _check_author(self, interaction: discord.Interaction) -> bool: async def _check_author(self, interaction: discord.Interaction) -> bool:
@@ -243,7 +286,9 @@ class TweetyView(discord.ui.View):
description="You can't modify someone else's tweet!", description="You can't modify someone else's tweet!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await interaction.response.send_message(embed=embed, ephemeral=True) await interaction.response.send_message(embed=embed, ephemeral=True)
return False return False
return True return True
@@ -269,10 +314,10 @@ class TweetyView(discord.ui.View):
for item in self.children: for item in self.children:
item.disabled = True item.disabled = True
def tweety_command(): def tweety_command():
@commands.hybrid_command( @commands.hybrid_command(
name="tweety", name="tweety", description="Convert a replied message to a tweet image."
description="Convert a replied message to a tweet image."
) )
@commands.cooldown(1, 10, commands.BucketType.user) @commands.cooldown(1, 10, commands.BucketType.user)
async def tweety(self, context): async def tweety(self, context):
@@ -288,36 +333,52 @@ def tweety_command():
description="You must reply to a message to use this command!", description="You must reply to a message to use this command!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.send(embed=embed) await context.send(embed=embed)
return return
try: try:
original_message = await context.channel.fetch_message(context.message.reference.message_id) original_message = await context.channel.fetch_message(
context.message.reference.message_id
)
processing_embed = discord.Embed( processing_embed = discord.Embed(
title="Tweet Generator (Processing)", title="Tweet Generator (Processing)",
description="<a:mariospin:1423677027013103709> Generating tweet... This may take a moment.", description="<a:mariospin:1423677027013103709> Generating tweet... This may take a moment.",
color=0x7289DA, color=0x7289DA,
) )
processing_embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") processing_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
processing_msg = await context.send(embed=processing_embed) processing_msg = await context.send(embed=processing_embed)
author = original_message.author author = original_message.author
display_name = author.display_name or author.name display_name = author.display_name or author.name
username = f"@{author.name}" username = f"@{author.name}"
avatar_url = str(author.avatar.url) if author.avatar else str(author.default_avatar.url) avatar_url = (
str(author.avatar.url)
if author.avatar
else str(author.default_avatar.url)
)
message_text = original_message.content message_text = original_message.content
for mention in original_message.mentions: for mention in original_message.mentions:
message_text = message_text.replace(f'<@{mention.id}>', f'@{mention.name}') message_text = message_text.replace(
message_text = message_text.replace(f'<@!{mention.id}>', f'@{mention.name}') f"<@{mention.id}>", f"@{mention.name}"
)
message_text = message_text.replace(
f"<@!{mention.id}>", f"@{mention.name}"
)
for role in original_message.role_mentions: for role in original_message.role_mentions:
message_text = message_text.replace(f'<@&{role.id}>', f'@{role.name}') message_text = message_text.replace(f"<@&{role.id}>", f"@{role.name}")
for channel in original_message.channel_mentions: for channel in original_message.channel_mentions:
message_text = message_text.replace(f'<#{channel.id}>', f'#{channel.name}') message_text = message_text.replace(
f"<#{channel.id}>", f"#{channel.name}"
)
if not message_text.strip(): if not message_text.strip():
await processing_msg.delete() await processing_msg.delete()
@@ -326,7 +387,9 @@ def tweety_command():
description="No text found! This command only works with text messages.", description="No text found! This command only works with text messages.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.send(embed=embed) await context.send(embed=embed)
return return
@@ -337,13 +400,15 @@ def tweety_command():
description=f"Message is too long! Maximum 300 characters allowed.\nYour message: {len(message_text)} characters", description=f"Message is too long! Maximum 300 characters allowed.\nYour message: {len(message_text)} characters",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.send(embed=embed) await context.send(embed=embed)
return return
message_text = break_long_words(message_text, max_word_length=50) message_text = break_long_words(message_text, max_word_length=50)
ny_tz = pytz.timezone('America/New_York') ny_tz = pytz.timezone("America/New_York")
msg_time_ny = original_message.created_at.astimezone(ny_tz) msg_time_ny = original_message.created_at.astimezone(ny_tz)
timestamp = msg_time_ny.strftime("%I:%M %p · %b %d, %Y").replace(" 0", " ") timestamp = msg_time_ny.strftime("%I:%M %p · %b %d, %Y").replace(" 0", " ")
tweet_data = { tweet_data = {
@@ -353,7 +418,7 @@ def tweety_command():
"avatar": avatar_url, "avatar": avatar_url,
"timestamp": timestamp, "timestamp": timestamp,
"verified": False, "verified": False,
"dark": False "dark": False,
} }
API_BASE_URL = "http://tweet.6969.pro" API_BASE_URL = "http://tweet.6969.pro"
@@ -363,9 +428,8 @@ def tweety_command():
async with session.post( async with session.post(
f"{API_BASE_URL}/api/render", f"{API_BASE_URL}/api/render",
json=tweet_data, json=tweet_data,
headers={"Content-Type": "application/json"} headers={"Content-Type": "application/json"},
) as response: ) as response:
if response.status != 200: if response.status != 200:
await processing_msg.delete() await processing_msg.delete()
error_text = await response.text() error_text = await response.text()
@@ -374,26 +438,37 @@ def tweety_command():
description=f"API Error ({response.status}): {error_text}", description=f"API Error ({response.status}): {error_text}",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
await context.send(embed=embed) await context.send(embed=embed)
return return
image_data = await response.read() image_data = await response.read()
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file: with tempfile.NamedTemporaryFile(
delete=False, suffix=".png"
) as temp_file:
temp_file.write(image_data) temp_file.write(image_data)
temp_file_path = temp_file.name temp_file_path = temp_file.name
await processing_msg.delete() await processing_msg.delete()
with open(temp_file_path, 'rb') as f: with open(temp_file_path, "rb") as f:
file = discord.File(f, filename=f"tweet_{author.name}_{int(datetime.now().timestamp())}.png") file = discord.File(
f,
filename=f"tweet_{author.name}_{int(datetime.now().timestamp())}.png",
)
embed = discord.Embed( embed = discord.Embed(
title="Tweet Generated", title="Tweet Generated",
description=f"<:error:1424007141768822824> Tweet sometimes may look a bit broken, im gonna rewrite the API another time... (it wasnt made for Syntrel in the first place)", description=f"<:error:1424007141768822824> Tweet sometimes may look a bit broken, im gonna rewrite the API another time... (it wasnt made for Syntrel in the first place)",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
embed.set_footer( embed.set_footer(
text=f"Requested by {context.author.name}", text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url, icon_url=context.author.display_avatar.url,
@@ -403,7 +478,7 @@ def tweety_command():
author_id=context.author.id, author_id=context.author.id,
original_message=original_message, original_message=original_message,
tweet_data=tweet_data, tweet_data=tweet_data,
api_url=API_BASE_URL api_url=API_BASE_URL,
) )
await context.send(embed=embed) await context.send(embed=embed)
@@ -419,7 +494,10 @@ def tweety_command():
description=f"Connection error: Could not reach tweet API", description=f"Connection error: Could not reach tweet API",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
await context.send(embed=embed) await context.send(embed=embed)
except Exception: except Exception:
await processing_msg.delete() await processing_msg.delete()
@@ -428,7 +506,10 @@ def tweety_command():
description="Error generating tweet image", description="Error generating tweet image",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
await context.send(embed=embed) await context.send(embed=embed)
except Exception: except Exception:
@@ -437,7 +518,9 @@ def tweety_command():
description="Error processing the message!", description="Error processing the message!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.send(embed=embed) await context.send(embed=embed)
return tweety return tweety

View File

@@ -25,9 +25,11 @@ class Melonx(commands.GroupCog, name="melonx"):
embed = discord.Embed( embed = discord.Embed(
title="MeloNX Commands", title="MeloNX Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x963155 color=0x963155,
)
embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
view = MelonxView(self.bot) view = MelonxView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -36,9 +38,11 @@ class Melonx(commands.GroupCog, name="melonx"):
embed = discord.Embed( embed = discord.Embed(
title="MeloNX Commands", title="MeloNX Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x963155 color=0x963155,
)
embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
view = MelonxView(self.bot) view = MelonxView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -87,76 +91,64 @@ class Melonx(commands.GroupCog, name="melonx"):
content = context.message.content.strip().lower() content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ") return content.startswith(f"{prefix}{group} ")
@app_commands.command( @app_commands.command(name="help", description="MeloNX troubleshooting help")
name="help",
description="MeloNX troubleshooting help"
)
async def help(self, interaction: discord.Interaction): async def help(self, interaction: discord.Interaction):
embed = discord.Embed( embed = discord.Embed(
title="MeloNX Commands", title="MeloNX Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x963155 color=0x963155,
)
embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
view = MelonxView(self.bot) view = MelonxView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True) await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="transfer", name="transfer",
description="How to transfer save files from other emulators or platforms" description="How to transfer save files from other emulators or platforms",
) )
async def transfer(self, context): async def transfer(self, context):
return await transfer_command()(self, context) return await transfer_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="mods", name="mods", description="How to install mods within MeloNX (Limited Support)"
description="How to install mods within MeloNX (Limited Support)"
) )
async def mods(self, context): async def mods(self, context):
return await mods_command()(self, context) return await mods_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="legal", description="Legality of emulators")
name="legal",
description="Legality of emulators"
)
async def legal(self, context): async def legal(self, context):
return await legal_command()(self, context) return await legal_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="gamecrash", description="Why does my game crash?")
name="gamecrash",
description="Why does my game crash?"
)
async def gamecrash(self, context): async def gamecrash(self, context):
return await crash_command()(self, context) return await crash_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="requirements", name="requirements", description="What does MeloNX require?"
description="What does MeloNX require?"
) )
async def requirements(self, context): async def requirements(self, context):
return await requirements_command()(self, context) return await requirements_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="error", name="error", description="What does this error message mean?"
description="What does this error message mean?"
) )
async def error(self, context): async def error(self, context):
return await error_command()(self, context) return await error_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="26", description="How can I run MeloNX on iOS 26?")
name="26",
description="How can I run MeloNX on iOS 26?"
)
async def ios26(self, context): async def ios26(self, context):
return await ios26_command()(self, context) return await ios26_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Melonx(bot) cog = Melonx(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -13,35 +13,40 @@ def error_command():
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description=( description=(
'# What does this error message mean?\n\n---\n\n' + "# What does this error message mean?\n\n---\n\n"
'**1. "MeloNX Crashed! System.SystemException: Cannot allocate memory"**' + + '**1. "MeloNX Crashed! System.SystemException: Cannot allocate memory"**'
'You likely don\'t have the increased memory limit entitlement enabled, are using an a12 chipset, and have 4GB or less of memory. You can see the status of the entitlement for MeloNX under the Settings tab.\n\n' + + "You likely don't have the increased memory limit entitlement enabled, are using an a12 chipset, and have 4GB or less of memory. You can see the status of the entitlement for MeloNX under the Settings tab.\n\n"
'**2. "MeloNX Crashed! LibHac.Common.HorizonResultException: ResultLoaderInvalidNso (2009-0005)"**' + + '**2. "MeloNX Crashed! LibHac.Common.HorizonResultException: ResultLoaderInvalidNso (2009-0005)"**'
'This is likely a bad game / update / or DLC dump. redump your files and try again.' + "This is likely a bad game / update / or DLC dump. redump your files and try again."
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by Meshal :D') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/error.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/error.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return error return error

View File

@@ -6,47 +6,50 @@ import time
def crash_command(): def crash_command():
@commands.hybrid_command( @commands.hybrid_command(name="gamecrash", description="Why does my game crash?")
name="gamecrash", description="Why does my game crash?"
)
async def crash(self, context): async def crash(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description=( description=(
'# "Why does my game crash?"\n\n---\n\n' + '# "Why does my game crash?"\n\n---\n\n'
'**This can be caused by multiple reasons:**\n' + + "**This can be caused by multiple reasons:**\n"
'- Not enough available ram\n' + + "- Not enough available ram\n"
'- You may have tried to update your firmware without updating your keys\n' + + "- You may have tried to update your firmware without updating your keys\n"
'- Game file is corrupted/broken\n' + + "- Game file is corrupted/broken\n"
'- Game requires a higher firmware+keys combination than you currently have\n' + + "- Game requires a higher firmware+keys combination than you currently have\n"
'- In rare cases some games also crash when not having the resolution set to 1x\n' + + "- In rare cases some games also crash when not having the resolution set to 1x\n"
'- The a12 chipset have a lot of issues at the moment\n' + + "- The a12 chipset have a lot of issues at the moment\n"
'- Shader cache isn\'t cleared after updating MeloNX\n' + + "- Shader cache isn't cleared after updating MeloNX\n"
'- iOS 15 and 16 are known to have some compatibility issues' + "- iOS 15 and 16 are known to have some compatibility issues"
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by Meshal :D') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/gamecrash.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/gamecrash.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return crash return crash

View File

@@ -6,47 +6,50 @@ import time
def ios26_command(): def ios26_command():
@commands.hybrid_command( @commands.hybrid_command(name="26", description="How can I run MeloNX on iOS 26?")
name="26", description="How can I run MeloNX on iOS 26?"
)
async def ios26(self, context): async def ios26(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description=( description=(
'# "How can I run MeloNX on iOS 26?"\n\n---\n\n' + '# "How can I run MeloNX on iOS 26?"\n\n---\n\n'
'### StikDebug\n' + + "### StikDebug\n"
'1. Make sure StikDebug is on the latest version.\n' + + "1. Make sure StikDebug is on the latest version.\n"
'2. Turn on "Picture in Picture" in StikDebug\'s settings.\n\n' + + '2. Turn on "Picture in Picture" in StikDebug\'s settings.\n\n'
'### MeloNX\n' + + "### MeloNX\n"
'Make sure you\'re on the latest version of MeloNX.\n' + + "Make sure you're on the latest version of MeloNX.\n"
'## Disclaimer:\n\n' + + "## Disclaimer:\n\n"
'If you\'re on iOS 18 or below, and emulation is essential to you:\n\n' + + "If you're on iOS 18 or below, and emulation is essential to you:\n\n"
'## <:error:1424007141768822824> DO NOT UPDATE <:error:1424007141768822824> \n\n' + + "## <:error:1424007141768822824> DO NOT UPDATE <:error:1424007141768822824> \n\n"
'iOS 26 has many issues related to emulation.' + "iOS 26 has many issues related to emulation."
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by Meshal :D') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/ios26.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/ios26.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return ios26 return ios26

View File

@@ -6,60 +6,62 @@ import time
def legal_command(): def legal_command():
@commands.hybrid_command( @commands.hybrid_command(name="legal", description="Legality of emulators.")
name="legal", description="Legality of emulators."
)
async def legal(self, context): async def legal(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description = ( description=(
'# Legality\n\n' + "# Legality\n\n"
'---\n\n' + + "---\n\n"
'## Overview\n' + + "## Overview\n"
'Emulators themselves are **legal**, as long as you use them with **legally dumped copies** of games **you** own, ' + + "Emulators themselves are **legal**, as long as you use them with **legally dumped copies** of games **you** own, "
'or with **homebrew software**.\n\n' + + "or with **homebrew software**.\n\n"
'Read about the landmark case [**Sony v. Bleem!** (2000)](https://www.copyright.gov/fair-use/summaries/sonycomputer-bleem-9thcir2000.pdf), ' + + "Read about the landmark case [**Sony v. Bleem!** (2000)](https://www.copyright.gov/fair-use/summaries/sonycomputer-bleem-9thcir2000.pdf), "
'which helped set the precedent for emulation being legal. You can also watch ' + + "which helped set the precedent for emulation being legal. You can also watch "
'[this video](https://www.youtube.com/watch?v=yj9Gk84jRiE) for more information.\n\n' + "[this video](https://www.youtube.com/watch?v=yj9Gk84jRiE) for more information.\n\n"
'## Legal Basis\n' + "## Legal Basis\n"
'According to the [**U.S. Copyright Act**](https://www.copyright.gov/title17/92chap1.html#117) ' + + "According to the [**U.S. Copyright Act**](https://www.copyright.gov/title17/92chap1.html#117) "
'(the law under which Discord operates), you **must own a legal copy** of any game you play on **MeloNX**.\n\n' + + "(the law under which Discord operates), you **must own a legal copy** of any game you play on **MeloNX**.\n\n"
'- Downloading games you do not own is considered **piracy** and is **illegal**.\n' + + "- Downloading games you do not own is considered **piracy** and is **illegal**.\n"
'- Even if another copy is identical, it still belongs to someone else, you are **not entitled** to it.\n\n' + + "- Even if another copy is identical, it still belongs to someone else, you are **not entitled** to it.\n\n"
'## Our Stance on Piracy\n' + + "## Our Stance on Piracy\n"
'We **do not support piracy**. Doing so would give Nintendo legal grounds to take us down.\n' + + "We **do not support piracy**. Doing so would give Nintendo legal grounds to take us down.\n"
'And yes — **Nintendo is aware of MeloNX\'s existence.**\n\n' + + "And yes — **Nintendo is aware of MeloNX's existence.**\n\n"
'We are not required to monitor user behavior, but we **strongly encourage** everyone to use only **legally obtained copies** of games.\n\n' + + "We are not required to monitor user behavior, but we **strongly encourage** everyone to use only **legally obtained copies** of games.\n\n"
'## Enforcement\n' + + "## Enforcement\n"
'If you are found using pirated games with MeloNX, you will be **banned** from this Discord server **without warning**.\n\n' + + "If you are found using pirated games with MeloNX, you will be **banned** from this Discord server **without warning**.\n\n"
'## Final Note\n' + + "## Final Note\n"
'Thank you for understanding and respecting the hard work that went into creating both the emulator MeloNX is built on, ' + + "Thank you for understanding and respecting the hard work that went into creating both the emulator MeloNX is built on, "
'and **MeloNX itself.**' + "and **MeloNX itself.**"
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by stossy11') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by stossy11")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/legal.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/legal.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return legal return legal

View File

@@ -58,44 +58,57 @@ class MelonxSelect(discord.ui.Select):
embed = discord.Embed( embed = discord.Embed(
title="Command Executed", title="Command Executed",
description=f"Successfully executed `/{command_name}`", description=f"Successfully executed `/{command_name}`",
color=0x00FF00 color=0x00FF00,
)
embed.set_author(
name="MeloNX",
icon_url="https://yes.nighty.works/raw/TLGaVa.png",
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except discord.Forbidden: except discord.Forbidden:
guild_info = f"server {interaction.guild.name} (ID: {interaction.guild.id})" if interaction.guild else "DM or private channel" guild_info = (
self.bot.logger.warning(f"Bot missing permissions in {guild_info} - cannot execute {command_name} command") f"server {interaction.guild.name} (ID: {interaction.guild.id})"
if interaction.guild
else "DM or private channel"
)
self.bot.logger.warning(
f"Bot missing permissions in {guild_info} - cannot execute {command_name} command"
)
if interaction.guild is None: if interaction.guild is None:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="This command cannot be executed in DMs.", description="This command cannot be executed in DMs.",
color=0xFF0000 color=0xFF0000,
) )
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Permission Error", title="Permission Error",
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xFF0000 color=0xFF0000,
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except Exception as e: except Exception as e:
self.bot.logger.error(f"Error executing {command_name} command: {e}") self.bot.logger.error(f"Error executing {command_name} command: {e}")
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="An error occurred while executing the command.", description="An error occurred while executing the command.",
color=0x963155 color=0x963155,
)
embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error", description="Command not found!", color=0x963155
description="Command not found!", )
color=0x963155 embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
@@ -116,10 +129,14 @@ def melonx_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -130,10 +147,14 @@ def melonx_command():
description="The bot needs send messages permissions in this channel.", description="The bot needs send messages permissions in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -141,14 +162,18 @@ def melonx_command():
embed = discord.Embed( embed = discord.Embed(
title="MeloNX Commands", title="MeloNX Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x963155 color=0x963155,
)
embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png")
view = MelonxView(self.bot) view = MelonxView(self.bot)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view, ephemeral=True) await context.interaction.response.send_message(
embed=embed, view=view, ephemeral=True
)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)

View File

@@ -13,41 +13,46 @@ def mods_command():
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description=( description=(
'# How do I install mods within MeloNX? (Limited Support)\n\n---\n\n' + "# How do I install mods within MeloNX? (Limited Support)\n\n---\n\n"
'### **romFS/exeFS mods**:\n' + + "### **romFS/exeFS mods**:\n"
'1. Obtain your title ID of your game by copying it from MeloNX, Hold down on the game and click game info.\n' + + "1. Obtain your title ID of your game by copying it from MeloNX, Hold down on the game and click game info.\n"
'2. Copy it and then go to Files-> MeloNX-> mods-> contents\n' + + "2. Copy it and then go to Files-> MeloNX-> mods-> contents\n"
'3. In the contents folder create a new folder and name it the title ID you copied earlier.\n' + + "3. In the contents folder create a new folder and name it the title ID you copied earlier.\n"
'4. Now place all your mods for that game in the folder you just made (these should be folders with the mod name, do not mess with the file structure of the mod after unzipping it.)\n\n' + + "4. Now place all your mods for that game in the folder you just made (these should be folders with the mod name, do not mess with the file structure of the mod after unzipping it.)\n\n"
'### **Atmosphere mods**: \n' + + "### **Atmosphere mods**: \n"
'1. Obtain your title ID of your game by copying it from MeloNX, Hold down on the game and click game info.\n' + + "1. Obtain your title ID of your game by copying it from MeloNX, Hold down on the game and click game info.\n"
'2. Copy it and then go to Files-> MeloNX-> sdcard-> atmosphere-> contents\n' + + "2. Copy it and then go to Files-> MeloNX-> sdcard-> atmosphere-> contents\n"
'3. In the contents folder create a new folder and name it the title ID you copied earlier.\n' + + "3. In the contents folder create a new folder and name it the title ID you copied earlier.\n"
'4. Now place all your mods for that game in the folder you just made (these should be folders with the mod name, do not mess with the file structure of the mod after unzipping it.)' + "4. Now place all your mods for that game in the folder you just made (these should be folders with the mod name, do not mess with the file structure of the mod after unzipping it.)"
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by Meshal :D') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/mods.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/mods.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return mods return mods

View File

@@ -13,36 +13,41 @@ def requirements_command():
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description=( description=(
'# "What does MeloNX require?"\n\n---\n\n' + '# "What does MeloNX require?"\n\n---\n\n'
'- JIT is **Mandatory**, because of this MeloNX will never be on the App Store / TestFlight\n' + + "- JIT is **Mandatory**, because of this MeloNX will never be on the App Store / TestFlight\n"
'- A Modded Nintendo Switch\n' + + "- A Modded Nintendo Switch\n"
'- The Increased Memory Limit Entitlement\n' + + "- The Increased Memory Limit Entitlement\n"
'- A device with a **A12/M1** chip and **4GB Ram** or higher\n' + + "- A device with a **A12/M1** chip and **4GB Ram** or higher\n"
'- TrollStore is supported with limited functionality for iOS 15' + "- TrollStore is supported with limited functionality for iOS 15"
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by Meshal :D') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/requirements.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/requirements.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return requirements return requirements

View File

@@ -7,52 +7,58 @@ import time
def transfer_command(): def transfer_command():
@commands.hybrid_command( @commands.hybrid_command(
name="transfer", description="How to transfer save files from other emulators or platforms" name="transfer",
description="How to transfer save files from other emulators or platforms",
) )
async def transfer(self, context): async def transfer(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x963155, color=0x963155,
description=( description=(
'# How do I transfer my save files from another emulator, my pc, or other platform?\n\n---\n\n' + "# How do I transfer my save files from another emulator, my pc, or other platform?\n\n---\n\n"
'### **Ryujinx Based**: \n' + + "### **Ryujinx Based**: \n"
'1. Go too Ryujinx\'s main directory -> copy and and transfer the **"bis"** folder to your iDevice.\n' + + '1. Go too Ryujinx\'s main directory -> copy and and transfer the **"bis"** folder to your iDevice.\n'
'2. Replace the **"bis"** folder in MeloNX with the one you transferred over.\n\n' + + '2. Replace the **"bis"** folder in MeloNX with the one you transferred over.\n\n'
'### **Yuzu Based**:\n' + + "### **Yuzu Based**:\n"
'1. Go to Yuzu\'s main directory and locate "**nand**" then go to -> users -> save\n' + + '1. Go to Yuzu\'s main directory and locate "**nand**" then go to -> users -> save\n'
'2. Get the **title ID** of the game you want to transfer to by locating the game on MeloNX, hold down on it and press "Game Info" \n' + + '2. Get the **title ID** of the game you want to transfer to by locating the game on MeloNX, hold down on it and press "Game Info" \n'
'3. Then search the title ID within the **save** folder\n' + + "3. Then search the title ID within the **save** folder\n"
'4. Open that folder labeled your title ID and copy of all of the contents to your iDevice\n' + + "4. Open that folder labeled your title ID and copy of all of the contents to your iDevice\n"
'5. Boot the game once in MeloNX so the save directories appear and is the latest created\n' + + "5. Boot the game once in MeloNX so the save directories appear and is the latest created\n"
'6. On your iDevice, go into files-> MeloNX -> bis -> user -> save\n' + + "6. On your iDevice, go into files-> MeloNX -> bis -> user -> save\n"
'7. In the save folder, there will be many folders named 0000001, 0000002, etc\n' + + "7. In the save folder, there will be many folders named 0000001, 0000002, etc\n"
'8. Sort by last modified or open each one too see the modified date/time of the files\n' + + "8. Sort by last modified or open each one too see the modified date/time of the files\n"
'9. Once you\'ve found the newest one, inside will be two folders named 1 and 0, one will have a brand new save file inside.\n' + + "9. Once you've found the newest one, inside will be two folders named 1 and 0, one will have a brand new save file inside.\n"
'10. drop the contents copied from the title ID folder in Yuzu into that directory and press "replace" when prompted.\n' + + '10. drop the contents copied from the title ID folder in Yuzu into that directory and press "replace" when prompted.\n'
'11. Launch the game again in MeloNX to verify the transfer.' + "11. Launch the game again in MeloNX to verify the transfer."
) ),
) )
embed.set_author(name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png") embed.set_author(
embed.set_footer(text=f'Last Edited by Meshal :D') name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
)
embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/transfer.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/melonx/transfer.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="MeloNX Discord", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://discord.gg/EMXB2XYQgA", discord.ui.Button(
emoji="<:Discord:1428762057758474280>" label="MeloNX Discord",
)) style=discord.ButtonStyle.primary,
url="https://discord.gg/EMXB2XYQgA",
emoji="<:Discord:1428762057758474280>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return transfer return transfer

View File

@@ -30,10 +30,16 @@ class Miscellaneous(commands.GroupCog, name="misc"):
embed = discord.Embed( embed = discord.Embed(
title="Miscellaneous Commands", title="Miscellaneous Commands",
description="Use `.misc <subcommand>` or `/misc <subcommand>`.", description="Use `.misc <subcommand>` or `/misc <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Miscellaneous", icon_url="https://yes.nighty.works/raw/YxMC0r.png"
)
embed.add_field(
name="Available",
value="dontasktoask, rr, depart, labubu, duck, tryitandsee, piracy, keanu, support, docs, sigma, silly, color",
inline=False,
) )
embed.set_author(name="Miscellaneous", icon_url="https://yes.nighty.works/raw/YxMC0r.png")
embed.add_field(name="Available", value="dontasktoask, rr, depart, labubu, duck, tryitandsee, piracy, keanu, support, docs, sigma, silly, color", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str): async def _invoke_hybrid(self, context: Context, name: str):
@@ -98,7 +104,9 @@ class Miscellaneous(commands.GroupCog, name="misc"):
await self._invoke_hybrid(context, "sigma") await self._invoke_hybrid(context, "sigma")
@miscellaneous_group.command(name="silly") @miscellaneous_group.command(name="silly")
async def miscellaneous_group_silly(self, context: Context, message_type: str = "regular"): async def miscellaneous_group_silly(
self, context: Context, message_type: str = "regular"
):
await self._invoke_hybrid(context, "silly", message_type=message_type) await self._invoke_hybrid(context, "silly", message_type=message_type)
@miscellaneous_group.command(name="color") @miscellaneous_group.command(name="color")
@@ -107,115 +115,79 @@ class Miscellaneous(commands.GroupCog, name="misc"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="dontasktoask", name="dontasktoask", description="Shows the 'Don't Ask to Ask' image."
description="Shows the 'Don't Ask to Ask' image."
) )
async def dontasktoask(self, context): async def dontasktoask(self, context):
return await dontasktoask_command()(self, context) return await dontasktoask_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="rr", description="Rickroll")
name="rr",
description="Rickroll"
)
async def rr(self, context): async def rr(self, context):
return await rr_command()(self, context) return await rr_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="depart", description="Show the departure meme")
name="depart",
description="Show the departure meme"
)
async def depart(self, context): async def depart(self, context):
return await depart_command()(self, context) return await depart_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="labubu", description="Labubu ASCII art")
name="labubu",
description="Labubu ASCII art"
)
async def labubu(self, context): async def labubu(self, context):
return await labubu_command()(self, context) return await labubu_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="duck", description="Duck ASCII art")
name="duck",
description="Duck ASCII art"
)
async def duck(self, context): async def duck(self, context):
return await duck_command()(self, context) return await duck_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="tryitandsee", description="Try it and see")
name="tryitandsee",
description="Try it and see"
)
async def tryitandsee(self, context): async def tryitandsee(self, context):
return await tryitandsee_command()(self, context) return await tryitandsee_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="piracy", description="FBI Anti Piracy Warning")
name="piracy",
description="FBI Anti Piracy Warning"
)
async def piracy(self, context): async def piracy(self, context):
return await piracy_command()(self, context) return await piracy_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="keanu", description="Reeves")
name="keanu",
description="Reeves"
)
async def keanu(self, context): async def keanu(self, context):
return await keanu_command()(self, context) return await keanu_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="support", description="Support?")
name="support",
description="Support?"
)
async def support(self, context): async def support(self, context):
return await support_command()(self, context) return await support_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="docs", description="Shows the docs image.")
name="docs",
description="Shows the docs image."
)
async def docs(self, context): async def docs(self, context):
return await docs_command()(self, context) return await docs_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="sigma", description="i feel so sigma!")
name="sigma",
description="i feel so sigma!"
)
async def sigma(self, context): async def sigma(self, context):
return await sigma_command()(self, context) return await sigma_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="silly", description="Sends a silly message :3")
name="silly", @app_commands.describe(message_type="Type of message to send (regular or animated)")
description="Sends a silly message :3" @app_commands.choices(
message_type=[
app_commands.Choice(name="Regular", value="regular"),
app_commands.Choice(name="Animated", value="animated"),
]
) )
@app_commands.describe(
message_type="Type of message to send (regular or animated)"
)
@app_commands.choices(message_type=[
app_commands.Choice(name="Regular", value="regular"),
app_commands.Choice(name="Animated", value="animated")
])
async def silly(self, context, message_type: str = "regular"): async def silly(self, context, message_type: str = "regular"):
return await silly_command()(self, context, message_type=message_type) return await silly_command()(self, context, message_type=message_type)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="color", description="Get a random color.")
name="color",
description="Get a random color."
)
async def color(self, context): async def color(self, context):
return await color_command()(self, context) return await color_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Miscellaneous(bot) cog = Miscellaneous(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -3,6 +3,7 @@ from discord.ext import commands
import random import random
import colorsys import colorsys
def color_command(): def color_command():
@commands.hybrid_command(name="color", description="Get a random color.") @commands.hybrid_command(name="color", description="Get a random color.")
async def color(self, context): async def color(self, context):
@@ -17,20 +18,34 @@ def color_command():
rgb_decimal = (r / 255, g / 255, b / 255) rgb_decimal = (r / 255, g / 255, b / 255)
h, l, s = colorsys.rgb_to_hls(rgb_decimal[0], rgb_decimal[1], rgb_decimal[2]) h, l, s = colorsys.rgb_to_hls(rgb_decimal[0], rgb_decimal[1], rgb_decimal[2])
h_hsv, s_hsv, v_hsv = colorsys.rgb_to_hsv(rgb_decimal[0], rgb_decimal[1], rgb_decimal[2]) h_hsv, s_hsv, v_hsv = colorsys.rgb_to_hsv(
rgb_decimal[0], rgb_decimal[1], rgb_decimal[2]
)
embed = discord.Embed(color=color) embed = discord.Embed(color=color)
embed.set_author(name="Random Color", icon_url="https://yes.nighty.works/raw/YxMC0r.png") embed.set_author(
name="Random Color", icon_url="https://yes.nighty.works/raw/YxMC0r.png"
)
embed.add_field(name="Hex", value=str(color)) embed.add_field(name="Hex", value=str(color))
embed.add_field(name="RGB", value=f"rgb({r}, {g}, {b})") embed.add_field(name="RGB", value=f"rgb({r}, {g}, {b})")
embed.add_field(name="RGB Decimal", value=f"{rgb_decimal[0]:.3f}, {rgb_decimal[1]:.3f}, {rgb_decimal[2]:.3f}") embed.add_field(
name="RGB Decimal",
value=f"{rgb_decimal[0]:.3f}, {rgb_decimal[1]:.3f}, {rgb_decimal[2]:.3f}",
)
embed.add_field(name="HSL", value=f"hsl({h*360:.0f}, {s*100:.0f}%, {l*100:.0f}%)") embed.add_field(
embed.add_field(name="HSV", value=f"hsv({h_hsv*360:.0f}, {s_hsv*100:.0f}%, {v_hsv*100:.0f}%)") name="HSL", value=f"hsl({h * 360:.0f}, {s * 100:.0f}%, {l * 100:.0f}%)"
)
embed.add_field(
name="HSV",
value=f"hsv({h_hsv * 360:.0f}, {s_hsv * 100:.0f}%, {v_hsv * 100:.0f}%)",
)
embed.add_field(name="Integer", value=str(random_color_int)) embed.add_field(name="Integer", value=str(random_color_int))
embed.set_thumbnail(url=f"https://singlecolorimage.com/get/{str(color).replace('#', '')}/150x150") embed.set_thumbnail(
url=f"https://singlecolorimage.com/get/{str(color).replace('#', '')}/150x150"
)
await context.send(embed=embed) await context.send(embed=embed)

View File

@@ -4,11 +4,9 @@ from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io
def docs_command(): def docs_command():
@commands.hybrid_command( @commands.hybrid_command(name="docs", description="Shows the docs image.")
name="docs",
description="Shows the docs image."
)
async def docs(self, context): async def docs(self, context):
url = "https://yes.nighty.works/raw/akdx0q.webp" url = "https://yes.nighty.works/raw/akdx0q.webp"
@@ -20,9 +18,15 @@ def docs_command():
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction
if not inter.response.is_done(): if not inter.response.is_done():
await inter.response.send_message("## Dont be like the rest, read the docs", file=file, ephemeral=False) await inter.response.send_message(
"## Dont be like the rest, read the docs",
file=file,
ephemeral=False,
)
else: else:
await inter.followup.send("## Dont be like the rest, read the docs", file=file, ephemeral=True) await inter.followup.send(
"## Dont be like the rest, read the docs", file=file, ephemeral=True
)
else: else:
await context.send("## Dont be like the rest, read the docs", file=file) await context.send("## Dont be like the rest, read the docs", file=file)

View File

@@ -4,10 +4,10 @@ from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io
def dontasktoask_command(): def dontasktoask_command():
@commands.hybrid_command( @commands.hybrid_command(
name="dontasktoask", name="dontasktoask", description="Shows the 'Don't Ask to Ask' image."
description="Shows the 'Don't Ask to Ask' image."
) )
async def dontasktoask(self, context): async def dontasktoask(self, context):
image_url = "https://yes.nighty.works/raw/KecbCr.jpg" image_url = "https://yes.nighty.works/raw/KecbCr.jpg"

View File

@@ -27,7 +27,9 @@ def duck_command():
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction
if not inter.response.is_done(): if not inter.response.is_done():
await inter.response.send_message(f"```ansi\n{duck_art}\n```", ephemeral=False) await inter.response.send_message(
f"```ansi\n{duck_art}\n```", ephemeral=False
)
else: else:
await inter.followup.send(f"```ansi\n{duck_art}\n```", ephemeral=True) await inter.followup.send(f"```ansi\n{duck_art}\n```", ephemeral=True)
else: else:

View File

@@ -28,14 +28,16 @@ def keanu_command():
"https://yes.nighty.works/raw/C7gy4v.jpg", "https://yes.nighty.works/raw/C7gy4v.jpg",
"https://yes.nighty.works/raw/XqHg1q.jpg", "https://yes.nighty.works/raw/XqHg1q.jpg",
"https://yes.nighty.works/raw/RUXNK7.png", "https://yes.nighty.works/raw/RUXNK7.png",
"https://yes.nighty.works/raw/CBNs9L.jpg" "https://yes.nighty.works/raw/CBNs9L.jpg",
] ]
embed = discord.Embed( embed = discord.Embed(
description="## Reeves", description="## Reeves",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Keanu", icon_url="https://yes.nighty.works/raw/YxMC0r.png") embed.set_author(
name="Keanu", icon_url="https://yes.nighty.works/raw/YxMC0r.png"
)
embed.set_image(url=random.choice(images)) embed.set_image(url=random.choice(images))
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction

View File

@@ -49,7 +49,9 @@ def labubu_command():
description=f"```ansi\n{labubu_art}\n```", description=f"```ansi\n{labubu_art}\n```",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Labubu", icon_url="https://yes.nighty.works/raw/YxMC0r.png") embed.set_author(
name="Labubu", icon_url="https://yes.nighty.works/raw/YxMC0r.png"
)
embed.set_footer(text=f"May look broken on mobile") embed.set_footer(text=f"May look broken on mobile")
if getattr(context, "interaction", None): if getattr(context, "interaction", None):

View File

@@ -4,11 +4,9 @@ from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io
def support_command(): def support_command():
@commands.hybrid_command( @commands.hybrid_command(name="support", description="Shows the support image.")
name="support",
description="Shows the support image."
)
async def support(self, context): async def support(self, context):
url = "https://yes.nighty.works/raw/wGzHIV.gif" url = "https://yes.nighty.works/raw/wGzHIV.gif"

View File

@@ -25,9 +25,13 @@ class Moderation(commands.GroupCog, name="moderation"):
embed = discord.Embed( embed = discord.Embed(
title="Moderation Commands", title="Moderation Commands",
description="Use `.moderation <subcommand>` or `/moderation <subcommand>`.", description="Use `.moderation <subcommand>` or `/moderation <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.add_field(
name="Available",
value="ban, kick, purge, warnings, archive, hackban, nick, timeout",
inline=False,
) )
embed.add_field(name="Available", value="ban, kick, purge, warnings, archive, hackban, nick, timeout", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
@@ -68,15 +72,28 @@ class Moderation(commands.GroupCog, name="moderation"):
return results[:25] return results[:25]
@moderation_group.command(name="ban") @moderation_group.command(name="ban")
async def moderation_group_ban(self, context: Context, user: discord.User, *, reason: str = "Not specified", delete_messages: str = "none"): async def moderation_group_ban(
await self._invoke_hybrid(context, "ban", user=user, reason=reason, delete_messages=delete_messages) self,
context: Context,
user: discord.User,
*,
reason: str = "Not specified",
delete_messages: str = "none",
):
await self._invoke_hybrid(
context, "ban", user=user, reason=reason, delete_messages=delete_messages
)
@moderation_group.command(name="kick") @moderation_group.command(name="kick")
async def moderation_group_kick(self, context: Context, user: discord.User, *, reason: str = "Not specified"): async def moderation_group_kick(
self, context: Context, user: discord.User, *, reason: str = "Not specified"
):
await self._invoke_hybrid(context, "kick", user=user, reason=reason) await self._invoke_hybrid(context, "kick", user=user, reason=reason)
@moderation_group.command(name="purge") @moderation_group.command(name="purge")
async def moderation_group_purge(self, context: Context, amount: int, user: discord.Member = None): async def moderation_group_purge(
self, context: Context, amount: int, user: discord.Member = None
):
await self._invoke_hybrid(context, "purge", amount=amount, user=user) await self._invoke_hybrid(context, "purge", amount=amount, user=user)
@moderation_group.command(name="warnings") @moderation_group.command(name="warnings")
@@ -88,45 +105,57 @@ class Moderation(commands.GroupCog, name="moderation"):
await self._invoke_hybrid(context, "archive", limit=limit) await self._invoke_hybrid(context, "archive", limit=limit)
@moderation_group.command(name="hackban") @moderation_group.command(name="hackban")
async def moderation_group_hackban(self, context: Context, user_id: str, *, reason: str = "Not specified"): async def moderation_group_hackban(
self, context: Context, user_id: str, *, reason: str = "Not specified"
):
await self._invoke_hybrid(context, "hackban", user_id=user_id, reason=reason) await self._invoke_hybrid(context, "hackban", user_id=user_id, reason=reason)
@moderation_group.command(name="nick") @moderation_group.command(name="nick")
async def moderation_group_nick(self, context: Context, user: discord.User, *, nickname: str = None): async def moderation_group_nick(
self, context: Context, user: discord.User, *, nickname: str = None
):
await self._invoke_hybrid(context, "nick", user=user, nickname=nickname) await self._invoke_hybrid(context, "nick", user=user, nickname=nickname)
@moderation_group.command(name="timeout") @moderation_group.command(name="timeout")
async def moderation_group_timeout(self, context: Context, user: discord.User, duration: str, *, reason: str = "Not specified"): async def moderation_group_timeout(
await self._invoke_hybrid(context, "timeout", user=user, duration=duration, reason=reason) self,
context: Context,
user: discord.User,
duration: str,
*,
reason: str = "Not specified",
):
await self._invoke_hybrid(
context, "timeout", user=user, duration=duration, reason=reason
)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="ban", description="Bans a user from the server.")
name="ban", async def ban(
description="Bans a user from the server." self,
) context,
async def ban(self, context, user: discord.User, *, reason: str = "Not specified", delete_messages: str = "none"): user: discord.User,
return await ban_command()(self, context, user=user, reason=reason, delete_messages=delete_messages) *,
reason: str = "Not specified",
delete_messages: str = "none",
):
return await ban_command()(
self, context, user=user, reason=reason, delete_messages=delete_messages
)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="kick", description="Kicks a user from the server.")
name="kick",
description="Kicks a user from the server."
)
async def kick(self, context, user: discord.User, *, reason: str = "Not specified"): async def kick(self, context, user: discord.User, *, reason: str = "Not specified"):
return await kick_command()(self, context, user=user, reason=reason) return await kick_command()(self, context, user=user, reason=reason)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="purge", description="Delete a number of messages.")
name="purge",
description="Delete a number of messages."
)
async def purge(self, context, amount: int, user: discord.Member = None): async def purge(self, context, amount: int, user: discord.Member = None):
return await purge_command()(self, context, amount=amount, user=user) return await purge_command()(self, context, amount=amount, user=user)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="warnings", name="warnings", description="Manage warnings of a user on a server."
description="Manage warnings of a user on a server."
) )
async def warnings(self, context): async def warnings(self, context):
return await warnings_command()(self, context) return await warnings_command()(self, context)
@@ -134,7 +163,7 @@ class Moderation(commands.GroupCog, name="moderation"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="archive", name="archive",
description="Archives in a text file the last messages with a chosen limit of messages." description="Archives in a text file the last messages with a chosen limit of messages.",
) )
async def archive(self, context, limit: int = 10): async def archive(self, context, limit: int = 10):
return await archive_command()(self, context, limit=limit) return await archive_command()(self, context, limit=limit)
@@ -142,23 +171,21 @@ class Moderation(commands.GroupCog, name="moderation"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="hackban", name="hackban",
description="Bans a user without the user having to be in the server." description="Bans a user without the user having to be in the server.",
) )
async def hackban(self, context, user_id: str, *, reason: str = "Not specified"): async def hackban(self, context, user_id: str, *, reason: str = "Not specified"):
return await hackban_command()(self, context, user_id=user_id, reason=reason) return await hackban_command()(self, context, user_id=user_id, reason=reason)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="nick", name="nick", description="Change the nickname of a user on a server."
description="Change the nickname of a user on a server."
) )
async def nick(self, context, user: discord.User, *, nickname: str = None): async def nick(self, context, user: discord.User, *, nickname: str = None):
return await nick_command()(self, context, user=user, nickname=nickname) return await nick_command()(self, context, user=user, nickname=nickname)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="timeout", name="timeout", description="Timeout a user for a specified duration."
description="Timeout a user for a specified duration."
) )
@app_commands.describe( @app_commands.describe(
user="The user that should be timed out.", user="The user that should be timed out.",
@@ -166,8 +193,18 @@ class Moderation(commands.GroupCog, name="moderation"):
reason="The reason why the user should be timed out.", reason="The reason why the user should be timed out.",
) )
@app_commands.autocomplete(duration=timeout_duration_autocomplete) @app_commands.autocomplete(duration=timeout_duration_autocomplete)
async def timeout(self, context, user: discord.User, duration: str, *, reason: str = "Not specified"): async def timeout(
return await timeout_command()(self, context, user=user, duration=duration, reason=reason) self,
context,
user: discord.User,
duration: str,
*,
reason: str = "Not specified",
):
return await timeout_command()(
self, context, user=user, duration=duration, reason=reason
)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Moderation(bot) cog = Moderation(bot)

View File

@@ -14,17 +14,24 @@ def ban_command():
reason="The reason why the user should be banned.", reason="The reason why the user should be banned.",
delete_messages="Delete messages from the user (choose time period).", delete_messages="Delete messages from the user (choose time period).",
) )
@app_commands.choices(delete_messages=[ @app_commands.choices(
app_commands.Choice(name="Don't delete any messages", value="none"), delete_messages=[
app_commands.Choice(name="Last 1 hour", value="1h"), app_commands.Choice(name="Don't delete any messages", value="none"),
app_commands.Choice(name="Last 6 hours", value="6h"), app_commands.Choice(name="Last 1 hour", value="1h"),
app_commands.Choice(name="Last 12 hours", value="12h"), app_commands.Choice(name="Last 6 hours", value="6h"),
app_commands.Choice(name="Last 24 hours", value="1d"), app_commands.Choice(name="Last 12 hours", value="12h"),
app_commands.Choice(name="Last 3 days", value="3d"), app_commands.Choice(name="Last 24 hours", value="1d"),
app_commands.Choice(name="Last 7 days", value="7d"), app_commands.Choice(name="Last 3 days", value="3d"),
]) app_commands.Choice(name="Last 7 days", value="7d"),
]
)
async def ban( async def ban(
self, context, user: discord.User, *, reason: str = "Not specified", delete_messages: str = "none" self,
context,
user: discord.User,
*,
reason: str = "Not specified",
delete_messages: str = "none",
): ):
try: try:
member = context.guild.get_member(user.id) member = context.guild.get_member(user.id)
@@ -38,7 +45,10 @@ def ban_command():
title="Ban", title="Ban",
description=f"**{user}** was banned by **{context.author}**!", description=f"**{user}** was banned by **{context.author}**!",
color=0x7289DA, color=0x7289DA,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
embed.add_field(name="Reason:", value=reason) embed.add_field(name="Reason:", value=reason)
await context.send(embed=embed) await context.send(embed=embed)
return return
@@ -47,7 +57,10 @@ def ban_command():
title="Error!", title="Error!",
description="I don't have permission to ban this user.", description="I don't have permission to ban this user.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
except Exception: except Exception:
@@ -55,16 +68,25 @@ def ban_command():
title="Error!", title="Error!",
description="An error occurred while trying to ban the user.", description="An error occurred while trying to ban the user.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
if not context.author.guild_permissions.ban_members and context.author != context.guild.owner: if (
not context.author.guild_permissions.ban_members
and context.author != context.guild.owner
):
embed = discord.Embed( embed = discord.Embed(
title="Missing Permissions!", title="Missing Permissions!",
description="You don't have the `Ban Members` permission to use this command.", description="You don't have the `Ban Members` permission to use this command.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -73,7 +95,10 @@ def ban_command():
title="Cannot Ban User", title="Cannot Ban User",
description="This user has a higher or equal role to me. Make sure my role is above theirs.", description="This user has a higher or equal role to me. Make sure my role is above theirs.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -83,7 +108,10 @@ def ban_command():
title="Cannot Ban User", title="Cannot Ban User",
description="You cannot ban this user as they have a higher or equal role to you.", description="You cannot ban this user as they have a higher or equal role to you.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -108,15 +136,22 @@ def ban_command():
title="Ban", title="Ban",
description=f"You were banned by **{context.author}** from **{context.guild.name}**!\nReason: {reason}", description=f"You were banned by **{context.author}** from **{context.guild.name}**!\nReason: {reason}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await member.send(embed=dm_embed) await member.send(embed=dm_embed)
except (discord.Forbidden, discord.HTTPException): except (discord.Forbidden, discord.HTTPException):
pass pass
if member: if member:
await member.ban(reason=reason, delete_message_days=delete_message_days) await member.ban(
reason=reason, delete_message_days=delete_message_days
)
else: else:
await context.guild.ban(user, reason=reason, delete_message_days=delete_message_days) await context.guild.ban(
user, reason=reason, delete_message_days=delete_message_days
)
if delete_all_messages: if delete_all_messages:
await self.delete_all_user_messages(context.guild, user.id) await self.delete_all_user_messages(context.guild, user.id)
@@ -125,15 +160,24 @@ def ban_command():
title="Ban", title="Ban",
description=f"**{user}** was banned by **{context.author}**!", description=f"**{user}** was banned by **{context.author}**!",
color=0x7289DA, color=0x7289DA,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
embed.add_field(name="Reason:", value=reason) embed.add_field(name="Reason:", value=reason)
if delete_messages != "none": if delete_messages != "none":
if delete_all_messages: if delete_all_messages:
embed.add_field(name="Messages Deleted:", value="All messages", inline=False) embed.add_field(
name="Messages Deleted:", value="All messages", inline=False
)
else: else:
delete_time_text = self.format_delete_time(delete_messages) delete_time_text = self.format_delete_time(delete_messages)
embed.add_field(name="Messages Deleted:", value=delete_time_text, inline=False) embed.add_field(
name="Messages Deleted:",
value=delete_time_text,
inline=False,
)
await context.send(embed=embed) await context.send(embed=embed)
@@ -142,7 +186,10 @@ def ban_command():
title="Error!", title="Error!",
description="I don't have permission to ban this user. Make sure my role is above theirs.", description="I don't have permission to ban this user. Make sure my role is above theirs.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except discord.HTTPException as e: except discord.HTTPException as e:
if "Cannot ban the owner of a guild" in str(e): if "Cannot ban the owner of a guild" in str(e):
@@ -150,20 +197,29 @@ def ban_command():
title="Cannot Ban User", title="Cannot Ban User",
description="You cannot ban the server owner.", description="You cannot ban the server owner.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description=f"Discord API error: {str(e)}", description=f"Discord API error: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Debug Error!", title="Debug Error!",
description=f"Error type: {type(e).__name__}\nError message: {str(e)}", description=f"Error type: {type(e).__name__}\nError message: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception as e:
@@ -171,14 +227,20 @@ def ban_command():
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
async def delete_all_user_messages(self, guild: discord.Guild, user_id: int) -> None: async def delete_all_user_messages(
self, guild: discord.Guild, user_id: int
) -> None:
for channel in guild.text_channels: for channel in guild.text_channels:
try: try:
permissions = channel.permissions_for(guild.me) permissions = channel.permissions_for(guild.me)
if not (permissions.read_message_history and permissions.manage_messages): if not (
permissions.read_message_history and permissions.manage_messages
):
continue continue
deleted = True deleted = True
@@ -190,7 +252,11 @@ def ban_command():
try: try:
await message.delete() await message.delete()
deleted = True deleted = True
except (discord.NotFound, discord.Forbidden, discord.HTTPException): except (
discord.NotFound,
discord.Forbidden,
discord.HTTPException,
):
continue continue
except (discord.Forbidden, discord.HTTPException): except (discord.Forbidden, discord.HTTPException):
break break
@@ -205,7 +271,7 @@ def ban_command():
"12h": "Last 12 hours", "12h": "Last 12 hours",
"1d": "Last 24 hours", "1d": "Last 24 hours",
"3d": "Last 3 days", "3d": "Last 3 days",
"7d": "Last 7 days" "7d": "Last 7 days",
} }
return time_formats.get(delete_option, "Unknown time period") return time_formats.get(delete_option, "Unknown time period")

View File

@@ -15,9 +15,7 @@ def hackban_command():
user_id="The user ID that should be banned.", user_id="The user ID that should be banned.",
reason="The reason why the user should be banned.", reason="The reason why the user should be banned.",
) )
async def hackban( async def hackban(self, context, user_id: str, *, reason: str = "Not specified"):
self, context, user_id: str, *, reason: str = "Not specified"
):
""" """
Bans a user without the user having to be in the server. Bans a user without the user having to be in the server.
@@ -34,7 +32,9 @@ def hackban_command():
title="Ban", title="Ban",
description=f"**{user}** (ID: {user_id}) was banned by **{context.author}**!", description=f"**{user}** (ID: {user_id}) was banned by **{context.author}**!",
color=0x7289DA, color=0x7289DA,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
embed.add_field(name="Reason:", value=reason) embed.add_field(name="Reason:", value=reason)
await context.send(embed=embed) await context.send(embed=embed)
except Exception: except Exception:
@@ -42,7 +42,9 @@ def hackban_command():
title="Error!", title="Error!",
description="An error occurred while trying to ban the user. Make sure ID is an existing ID that belongs to a user.", description="An error occurred while trying to ban the user. Make sure ID is an existing ID that belongs to a user.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await context.send(embed=embed) await context.send(embed=embed)
return hackban return hackban

View File

@@ -13,9 +13,7 @@ def kick_command():
user="The user that should be kicked.", user="The user that should be kicked.",
reason="The reason why the user should be kicked.", reason="The reason why the user should be kicked.",
) )
async def kick( async def kick(self, context, user: discord.User, *, reason: str = "Not specified"):
self, context, user: discord.User, *, reason: str = "Not specified"
):
try: try:
member = context.guild.get_member(user.id) member = context.guild.get_member(user.id)
if not member: if not member:
@@ -26,16 +24,25 @@ def kick_command():
title="Error!", title="Error!",
description="This user is not in the server.", description="This user is not in the server.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
if not context.author.guild_permissions.kick_members and context.author != context.guild.owner: if (
not context.author.guild_permissions.kick_members
and context.author != context.guild.owner
):
embed = discord.Embed( embed = discord.Embed(
title="Missing Permissions!", title="Missing Permissions!",
description="You don't have the `Kick Members` permission to use this command.", description="You don't have the `Kick Members` permission to use this command.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -44,7 +51,10 @@ def kick_command():
title="Cannot Kick User", title="Cannot Kick User",
description="This user has a higher or equal role to me. Make sure my role is above theirs.", description="This user has a higher or equal role to me. Make sure my role is above theirs.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -54,7 +64,10 @@ def kick_command():
title="Cannot Kick User", title="Cannot Kick User",
description="You cannot kick this user as they have a higher or equal role to you.", description="You cannot kick this user as they have a higher or equal role to you.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -66,8 +79,10 @@ def kick_command():
title="Kick", title="Kick",
description=f"You were kicked by **{context.author}** from **{context.guild.name}**!\nReason: {reason}", description=f"You were kicked by **{context.author}** from **{context.guild.name}**!\nReason: {reason}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
) )
except (discord.Forbidden, discord.HTTPException): except (discord.Forbidden, discord.HTTPException):
pass pass
@@ -78,7 +93,10 @@ def kick_command():
title="Kick", title="Kick",
description=f"**{user}** was kicked by **{context.author}**!", description=f"**{user}** was kicked by **{context.author}**!",
color=0x7289DA, color=0x7289DA,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
embed.add_field(name="Reason:", value=reason) embed.add_field(name="Reason:", value=reason)
await context.send(embed=embed) await context.send(embed=embed)
@@ -88,7 +106,10 @@ def kick_command():
title="Error!", title="Error!",
description="I don't have permission to kick this user. Make sure my role is above theirs.", description="I don't have permission to kick this user. Make sure my role is above theirs.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except discord.HTTPException as e: except discord.HTTPException as e:
if "Cannot kick the owner of a guild" in str(e): if "Cannot kick the owner of a guild" in str(e):
@@ -96,20 +117,29 @@ def kick_command():
title="Cannot Kick User", title="Cannot Kick User",
description="You cannot kick the server owner.", description="You cannot kick the server owner.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description=f"Discord API error: {str(e)}", description=f"Discord API error: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Debug Error!", title="Debug Error!",
description=f"Error type: {type(e).__name__}\nError message: {str(e)}", description=f"Error type: {type(e).__name__}\nError message: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception as e:
@@ -117,7 +147,9 @@ def kick_command():
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return kick return kick

View File

@@ -13,9 +13,7 @@ def nick_command():
user="The user that should have a new nickname.", user="The user that should have a new nickname.",
nickname="The new nickname that should be set.", nickname="The new nickname that should be set.",
) )
async def nick( async def nick(self, context, user: discord.User, *, nickname: str = None):
self, context, user: discord.User, *, nickname: str = None
):
""" """
Change the nickname of a user on a server. Change the nickname of a user on a server.
@@ -28,7 +26,9 @@ def nick_command():
title="Missing Permissions!", title="Missing Permissions!",
description="You are missing the permission(s) `manage_nicknames` to execute this command!", description="You are missing the permission(s) `manage_nicknames` to execute this command!",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
return await context.send(embed=embed, ephemeral=True) return await context.send(embed=embed, ephemeral=True)
if not context.guild.me.guild_permissions.manage_nicknames: if not context.guild.me.guild_permissions.manage_nicknames:
@@ -36,7 +36,9 @@ def nick_command():
title="Missing Permissions!", title="Missing Permissions!",
description="I am missing the permission(s) `manage_nicknames` to execute this command!", description="I am missing the permission(s) `manage_nicknames` to execute this command!",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
return await context.send(embed=embed, ephemeral=True) return await context.send(embed=embed, ephemeral=True)
member = context.guild.get_member(user.id) or await context.guild.fetch_member( member = context.guild.get_member(user.id) or await context.guild.fetch_member(
@@ -48,14 +50,18 @@ def nick_command():
title="Nickname", title="Nickname",
description=f"**{member}'s** new nickname is **{nickname}**!", description=f"**{member}'s** new nickname is **{nickname}**!",
color=0x7289DA, color=0x7289DA,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await context.send(embed=embed) await context.send(embed=embed)
except: except:
embed = discord.Embed( embed = discord.Embed(
title="Missing Permissions!", title="Missing Permissions!",
description="An error occurred while trying to change the nickname of the user. Make sure my role is above the role of the user you want to change the nickname.", description="An error occurred while trying to change the nickname of the user. Make sure my role is above the role of the user you want to change the nickname.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return nick return nick

View File

@@ -3,6 +3,7 @@ from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
def purge_command(): def purge_command():
@commands.hybrid_command( @commands.hybrid_command(
name="purge", name="purge",
@@ -12,7 +13,7 @@ def purge_command():
@commands.bot_has_permissions(manage_messages=True) @commands.bot_has_permissions(manage_messages=True)
@app_commands.describe( @app_commands.describe(
amount="The amount of messages that should be deleted.", amount="The amount of messages that should be deleted.",
user="The user whose messages should be deleted (optional)." user="The user whose messages should be deleted (optional).",
) )
async def purge(self, context, amount: int, user: discord.Member = None): async def purge(self, context, amount: int, user: discord.Member = None):
if context.interaction: if context.interaction:
@@ -34,10 +35,13 @@ def purge_command():
embed = discord.Embed( embed = discord.Embed(
title="Purge", title="Purge",
description=f"**{context.author}** cleared **{len(purged_messages)}** messages!" + (f" from **{user}**" if user else ""), description=f"**{context.author}** cleared **{len(purged_messages)}** messages!"
+ (f" from **{user}**" if user else ""),
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") embed.set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
if context.interaction: if context.interaction:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)

View File

@@ -13,6 +13,7 @@ def timeout_command():
app_commands.Choice(name="1 day", value="1d"), app_commands.Choice(name="1 day", value="1d"),
app_commands.Choice(name="1 week", value="1w"), app_commands.Choice(name="1 week", value="1w"),
] ]
@commands.hybrid_command( @commands.hybrid_command(
name="timeout", name="timeout",
description="Timeout a user for a specified duration.", description="Timeout a user for a specified duration.",
@@ -24,7 +25,12 @@ def timeout_command():
) )
@app_commands.choices(duration=DURATION_CHOICES) @app_commands.choices(duration=DURATION_CHOICES)
async def timeout( async def timeout(
self, context, user: discord.User, duration: str, *, reason: str = "Not specified" self,
context,
user: discord.User,
duration: str,
*,
reason: str = "Not specified",
): ):
try: try:
member = context.guild.get_member(user.id) member = context.guild.get_member(user.id)
@@ -36,16 +42,25 @@ def timeout_command():
title="Error!", title="Error!",
description="This user is not in the server.", description="This user is not in the server.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
if not context.author.guild_permissions.moderate_members and context.author != context.guild.owner: if (
not context.author.guild_permissions.moderate_members
and context.author != context.guild.owner
):
embed = discord.Embed( embed = discord.Embed(
title="Missing Permissions!", title="Missing Permissions!",
description="You don't have the `Timeout Members` permission to use this command.", description="You don't have the `Timeout Members` permission to use this command.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -54,7 +69,10 @@ def timeout_command():
title="Cannot Timeout User", title="Cannot Timeout User",
description="This user has a higher or equal role to me. Make sure my role is above theirs.", description="This user has a higher or equal role to me. Make sure my role is above theirs.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -64,7 +82,10 @@ def timeout_command():
title="Cannot Timeout User", title="Cannot Timeout User",
description="You cannot timeout this user as they have a higher or equal role to you.", description="You cannot timeout this user as they have a higher or equal role to you.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -74,7 +95,10 @@ def timeout_command():
title="Invalid Duration", title="Invalid Duration",
description="Choose one of: 60 secs, 5 mins, 10 mins, 1 hour, 1 day, 1 week.", description="Choose one of: 60 secs, 5 mins, 10 mins, 1 hour, 1 day, 1 week.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -89,9 +113,14 @@ def timeout_command():
title="Timeout", title="Timeout",
description=f"**{user}** was timed out by **{context.author}**!", description=f"**{user}** was timed out by **{context.author}**!",
color=0x7289DA, color=0x7289DA,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
embed.add_field(name="Reason:", value=reason) embed.add_field(name="Reason:", value=reason)
embed.add_field(name="Duration:", value=_format_duration(duration), inline=False) embed.add_field(
name="Duration:", value=_format_duration(duration), inline=False
)
await context.send(embed=embed) await context.send(embed=embed)
except discord.Forbidden: except discord.Forbidden:
@@ -99,21 +128,30 @@ def timeout_command():
title="Error!", title="Error!",
description="I don't have permission to timeout this user. Make sure my role is above theirs.", description="I don't have permission to timeout this user. Make sure my role is above theirs.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except discord.HTTPException as e: except discord.HTTPException as e:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description=f"Discord API error: {str(e)}", description=f"Discord API error: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Debug Error!", title="Debug Error!",
description=f"Error type: {type(e).__name__}\nError message: {str(e)}", description=f"Error type: {type(e).__name__}\nError message: {str(e)}",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation",
icon_url="https://yes.nighty.works/raw/CPKHQd.png",
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception: except Exception:
@@ -121,13 +159,19 @@ def timeout_command():
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
@timeout.autocomplete("duration") @timeout.autocomplete("duration")
async def duration_autocomplete(interaction: discord.Interaction, current: str): async def duration_autocomplete(interaction: discord.Interaction, current: str):
query = (current or "").lower() query = (current or "").lower()
filtered = [c for c in DURATION_CHOICES if query in c.name.lower() or query in c.value.lower()] filtered = [
c
for c in DURATION_CHOICES
if query in c.name.lower() or query in c.value.lower()
]
return filtered[:25] return filtered[:25]
return timeout return timeout
@@ -172,5 +216,3 @@ def _format_duration(duration: str) -> str:
return f"{value} seconds" return f"{value} seconds"
except Exception: except Exception:
return duration return duration

View File

@@ -5,13 +5,17 @@ from discord.ext.commands import Context
def warnings_command(): def warnings_command():
async def send_embed(context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -30,7 +34,9 @@ def warnings_command():
title="Missing Permissions!", title="Missing Permissions!",
description="You are missing the permission(s) `manage_messages` to execute this command!", description="You are missing the permission(s) `manage_messages` to execute this command!",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
return await self.send_embed(context, embed, ephemeral=True) return await self.send_embed(context, embed, ephemeral=True)
if context.invoked_subcommand is None: if context.invoked_subcommand is None:
@@ -39,7 +45,9 @@ def warnings_command():
description="Please specify a subcommand.\n\n**Subcommands:**\n`add` - Add a warning to a user.\n`remove` - Remove a warning from a user.\n`list` - List all warnings of a user.", description="Please specify a subcommand.\n\n**Subcommands:**\n`add` - Add a warning to a user.\n`remove` - Remove a warning from a user.\n`list` - List all warnings of a user.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") embed.set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
@warning.command( @warning.command(
@@ -65,7 +73,9 @@ def warnings_command():
title="Missing Permissions!", title="Missing Permissions!",
description="You are missing the permission(s) `manage_messages` to execute this command!", description="You are missing the permission(s) `manage_messages` to execute this command!",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
return await self.send_embed(context, embed, ephemeral=True) return await self.send_embed(context, embed, ephemeral=True)
member = context.guild.get_member(user.id) or await context.guild.fetch_member( member = context.guild.get_member(user.id) or await context.guild.fetch_member(
user.id user.id
@@ -78,7 +88,9 @@ def warnings_command():
description=f"**{member}** was warned by **{context.author}**!\nTotal warns for this user: {total}", description=f"**{member}** was warned by **{context.author}**!\nTotal warns for this user: {total}",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") embed.set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
embed.add_field(name="Reason:", value=reason) embed.add_field(name="Reason:", value=reason)
await self.send_embed(context, embed) await self.send_embed(context, embed)
try: try:
@@ -87,7 +99,9 @@ def warnings_command():
description=f"You were warned by **{context.author}** in **{context.guild.name}**!\nReason: {reason}", description=f"You were warned by **{context.author}** in **{context.guild.name}**!\nReason: {reason}",
color=0xE02B2B, color=0xE02B2B,
) )
dm_embed.set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") dm_embed.set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await member.send(embed=dm_embed) await member.send(embed=dm_embed)
except: except:
fallback = discord.Embed( fallback = discord.Embed(
@@ -120,7 +134,9 @@ def warnings_command():
title="Missing Permissions!", title="Missing Permissions!",
description="You are missing the permission(s) `manage_messages` to execute this command!", description="You are missing the permission(s) `manage_messages` to execute this command!",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
return await self.send_embed(context, embed, ephemeral=True) return await self.send_embed(context, embed, ephemeral=True)
member = context.guild.get_member(user.id) or await context.guild.fetch_member( member = context.guild.get_member(user.id) or await context.guild.fetch_member(
user.id user.id
@@ -131,7 +147,9 @@ def warnings_command():
description=f"Removed the warning **#{warn_id}** from **{member}**!\nTotal warns for this user: {total}", description=f"Removed the warning **#{warn_id}** from **{member}**!\nTotal warns for this user: {total}",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") embed.set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
@warning.command( @warning.command(
@@ -151,11 +169,15 @@ def warnings_command():
title="Missing Permissions!", title="Missing Permissions!",
description="You are missing the permission(s) `manage_messages` to execute this command!", description="You are missing the permission(s) `manage_messages` to execute this command!",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") ).set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
return await self.send_embed(context, embed, ephemeral=True) return await self.send_embed(context, embed, ephemeral=True)
warnings_list = await self.bot.database.get_warnings(user.id, context.guild.id) warnings_list = await self.bot.database.get_warnings(user.id, context.guild.id)
embed = discord.Embed(title=f"Warnings of {user}", color=0x7289DA) embed = discord.Embed(title=f"Warnings of {user}", color=0x7289DA)
embed.set_author(name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png") embed.set_author(
name="Moderation", icon_url="https://yes.nighty.works/raw/CPKHQd.png"
)
description = "" description = ""
if len(warnings_list) == 0: if len(warnings_list) == 0:
description = "This user has no warnings." description = "This user has no warnings."
@@ -165,6 +187,4 @@ def warnings_command():
embed.description = description embed.description = description
await self.send_embed(context, embed) await self.send_embed(context, embed)
return warning return warning

View File

@@ -8,13 +8,17 @@ class CogManagement(commands.Cog, name="cog_management"):
def __init__(self, bot) -> None: def __init__(self, bot) -> None:
self.bot = bot self.bot = bot
async def send_embed(self, context: Context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
self, context: Context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -38,15 +42,20 @@ class CogManagement(commands.Cog, name="cog_management"):
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description=f"Could not load the `{cog}` cog.\n```{str(e)}```", color=0xE02B2B description=f"Could not load the `{cog}` cog.\n```{str(e)}```",
color=0xE02B2B,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp")
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
return return
embed = discord.Embed( embed = discord.Embed(
description=f"Successfully loaded the `{cog}` cog.", color=0x7289DA description=f"Successfully loaded the `{cog}` cog.", color=0x7289DA
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
@commands.hybrid_command( @commands.hybrid_command(
@@ -69,15 +78,20 @@ class CogManagement(commands.Cog, name="cog_management"):
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description=f"Could not unload the `{cog}` cog.\n```{str(e)}```", color=0xE02B2B description=f"Could not unload the `{cog}` cog.\n```{str(e)}```",
color=0xE02B2B,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp")
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
return return
embed = discord.Embed( embed = discord.Embed(
description=f"Successfully unloaded the `{cog}` cog.", color=0x7289DA description=f"Successfully unloaded the `{cog}` cog.", color=0x7289DA
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
@commands.hybrid_command( @commands.hybrid_command(
@@ -100,16 +114,22 @@ class CogManagement(commands.Cog, name="cog_management"):
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description=f"Could not reload the `{cog}` cog.\n```{str(e)}```", color=0xE02B2B description=f"Could not reload the `{cog}` cog.\n```{str(e)}```",
color=0xE02B2B,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp")
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
return return
embed = discord.Embed( embed = discord.Embed(
title="Cog Management", title="Cog Management",
description=f"Successfully reloaded the `{cog}` cog.", color=0x7289DA description=f"Successfully reloaded the `{cog}` cog.",
color=0x7289DA,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp")
await self.send_embed(context, embed) await self.send_embed(context, embed)
async def cog_command_error(self, context: Context, error) -> None: async def cog_command_error(self, context: Context, error) -> None:
@@ -117,9 +137,11 @@ class CogManagement(commands.Cog, name="cog_management"):
embed = discord.Embed( embed = discord.Embed(
title="Permission Denied", title="Permission Denied",
description="You are not the owner of the bot!", description="You are not the owner of the bot!",
color=0xE02B2B color=0xE02B2B,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp")
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
else: else:
raise error raise error

View File

@@ -10,13 +10,17 @@ class Invite(commands.Cog, name="invite"):
def __init__(self, bot) -> None: def __init__(self, bot) -> None:
self.bot = bot self.bot = bot
async def send_embed(self, context: Context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
self, context: Context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -38,8 +42,14 @@ class Invite(commands.Cog, name="invite"):
await context.send("Bot is not ready. Try again shortly.") await context.send("Bot is not ready. Try again shortly.")
return return
invite_link = os.getenv("INVITE_LINK") invite_link = os.getenv("INVITE_LINK")
embed = discord.Embed(title="Install", description=f"Install me by clicking [here]({invite_link}).", color=0x7289DA) embed = discord.Embed(
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") title="Install",
description=f"Install me by clicking [here]({invite_link}).",
color=0x7289DA,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=False) await self.send_embed(context, embed, ephemeral=False)
@@ -48,9 +58,11 @@ class Invite(commands.Cog, name="invite"):
embed = discord.Embed( embed = discord.Embed(
title="Permission Denied", title="Permission Denied",
description="You are not the owner of this bot.", description="You are not the owner of this bot.",
color=0xE02B2B color=0xE02B2B,
)
embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp")
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
else: else:
raise error raise error

View File

@@ -11,17 +11,23 @@ class Logs(commands.Cog, name="logs"):
def __init__(self, bot) -> None: def __init__(self, bot) -> None:
self.bot = bot self.bot = bot
async def send_embed(self, context: Context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
self, context: Context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
async def send_file(self, context: Context, *, file: discord.File, ephemeral: bool = False) -> None: async def send_file(
self, context: Context, *, file: discord.File, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
@@ -35,7 +41,9 @@ class Logs(commands.Cog, name="logs"):
name="logs", name="logs",
description="View the bot's log file", description="View the bot's log file",
) )
@app_commands.describe(lines="Number of lines to read from the end of the log file (default: 50, max: 200)") @app_commands.describe(
lines="Number of lines to read from the end of the log file (default: 50, max: 200)"
)
@app_commands.allowed_contexts(guilds=True, dms=True, private_channels=True) @app_commands.allowed_contexts(guilds=True, dms=True, private_channels=True)
@app_commands.allowed_installs(guilds=True, users=True) @app_commands.allowed_installs(guilds=True, users=True)
@is_owner_or_friend() @is_owner_or_friend()
@@ -48,7 +56,10 @@ class Logs(commands.Cog, name="logs"):
log_file_path = os.getenv("LOG_FILE", "logs/discord.log") log_file_path = os.getenv("LOG_FILE", "logs/discord.log")
if not os.path.isabs(log_file_path): if not os.path.isabs(log_file_path):
log_file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), log_file_path) log_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
log_file_path,
)
try: try:
if not os.path.exists(log_file_path): if not os.path.exists(log_file_path):
@@ -57,11 +68,13 @@ class Logs(commands.Cog, name="logs"):
description=f"Log file not found at: `{log_file_path}`", description=f"Log file not found at: `{log_file_path}`",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
return return
with open(log_file_path, 'r', encoding='utf-8', errors='replace') as f: with open(log_file_path, "r", encoding="utf-8", errors="replace") as f:
all_lines = f.readlines() all_lines = f.readlines()
if not all_lines: if not all_lines:
@@ -70,17 +83,23 @@ class Logs(commands.Cog, name="logs"):
description="Log file is empty.", description="Log file is empty.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
return return
selected_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines selected_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
log_content = ''.join(selected_lines) log_content = "".join(selected_lines)
log_file = f"logs.txt" log_file = f"logs.txt"
with open(log_file, "w", encoding="utf-8") as f: with open(log_file, "w", encoding="utf-8") as f:
f.write(f"Bot logs extracted at {discord.utils.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n") f.write(
f.write(f"Last {len(selected_lines)} lines from {os.path.basename(log_file_path)}\n") f"Bot logs extracted at {discord.utils.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n"
)
f.write(
f"Last {len(selected_lines)} lines from {os.path.basename(log_file_path)}\n"
)
f.write(f"Total lines in log file: {len(all_lines)}\n") f.write(f"Total lines in log file: {len(all_lines)}\n")
f.write("-" * 50 + "\n\n") f.write("-" * 50 + "\n\n")
f.write(ascii_plain + "\n\n") f.write(ascii_plain + "\n\n")
@@ -97,7 +116,9 @@ class Logs(commands.Cog, name="logs"):
description=f"Permission denied when trying to read log file: `{log_file_path}`", description=f"Permission denied when trying to read log file: `{log_file_path}`",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
except Exception as e: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
@@ -105,7 +126,9 @@ class Logs(commands.Cog, name="logs"):
description=f"An error occurred while reading the log file:\n```\n{str(e)}\n```", description=f"An error occurred while reading the log file:\n```\n{str(e)}\n```",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
async def cog_command_error(self, context: Context, error) -> None: async def cog_command_error(self, context: Context, error) -> None:
@@ -115,7 +138,9 @@ class Logs(commands.Cog, name="logs"):
description="You are not the owner of this bot!", description="You are not the owner of this bot!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
else: else:
raise error raise error
@@ -123,4 +148,3 @@ class Logs(commands.Cog, name="logs"):
async def setup(bot) -> None: async def setup(bot) -> None:
await bot.add_cog(Logs(bot)) await bot.add_cog(Logs(bot))

View File

@@ -9,13 +9,24 @@ class Say(commands.Cog, name="say"):
def __init__(self, bot) -> None: def __init__(self, bot) -> None:
self.bot = bot self.bot = bot
async def send_embed(self, context: Context, embed: discord.Embed, *, ephemeral: bool = False, allowed_mentions: discord.AllowedMentions = None) -> None: async def send_embed(
self,
context: Context,
embed: discord.Embed,
*,
ephemeral: bool = False,
allowed_mentions: discord.AllowedMentions = None,
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral, allowed_mentions=allowed_mentions) await interaction.followup.send(
embed=embed, ephemeral=ephemeral, allowed_mentions=allowed_mentions
)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral, allowed_mentions=allowed_mentions) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral, allowed_mentions=allowed_mentions
)
else: else:
await context.send(embed=embed, allowed_mentions=allowed_mentions) await context.send(embed=embed, allowed_mentions=allowed_mentions)
@@ -57,7 +68,9 @@ class Say(commands.Cog, name="say"):
except: except:
pass pass
except discord.Forbidden: except discord.Forbidden:
await interaction.followup.send(message, allowed_mentions=allowed_mentions) await interaction.followup.send(
message, allowed_mentions=allowed_mentions
)
else: else:
try: try:
await context.message.delete() await context.message.delete()
@@ -95,21 +108,27 @@ class Say(commands.Cog, name="say"):
description=message, description=message,
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
is_in_guild = context.guild is not None is_in_guild = context.guild is not None
await interaction.response.defer(ephemeral=is_in_guild) await interaction.response.defer(ephemeral=is_in_guild)
try: try:
await context.channel.send(embed=embed, allowed_mentions=allowed_mentions) await context.channel.send(
embed=embed, allowed_mentions=allowed_mentions
)
if is_in_guild: if is_in_guild:
try: try:
await interaction.delete_original_response() await interaction.delete_original_response()
except: except:
pass pass
except discord.Forbidden: except discord.Forbidden:
await interaction.followup.send(embed=embed, allowed_mentions=allowed_mentions) await interaction.followup.send(
embed=embed, allowed_mentions=allowed_mentions
)
else: else:
try: try:
await context.message.delete() await context.message.delete()
@@ -117,7 +136,6 @@ class Say(commands.Cog, name="say"):
pass pass
await context.send(embed=embed, allowed_mentions=allowed_mentions) await context.send(embed=embed, allowed_mentions=allowed_mentions)
async def cog_command_error(self, context: Context, error) -> None: async def cog_command_error(self, context: Context, error) -> None:
if isinstance(error, (commands.NotOwner, commands.CheckFailure)): if isinstance(error, (commands.NotOwner, commands.CheckFailure)):
embed = discord.Embed( embed = discord.Embed(
@@ -125,7 +143,9 @@ class Say(commands.Cog, name="say"):
description="You are not the owner of this bot!", description="You are not the owner of this bot!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
else: else:
raise error raise error

View File

@@ -10,13 +10,17 @@ class Shutdown(commands.Cog, name="shutdown"):
def __init__(self, bot) -> None: def __init__(self, bot) -> None:
self.bot = bot self.bot = bot
async def send_embed(self, context: Context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
self, context: Context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -59,7 +63,9 @@ class Shutdown(commands.Cog, name="shutdown"):
description="You are not the owner of this bot!", description="You are not the owner of this bot!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
else: else:
raise error raise error

View File

@@ -8,13 +8,17 @@ class Sync(commands.Cog, name="sync"):
def __init__(self, bot) -> None: def __init__(self, bot) -> None:
self.bot = bot self.bot = bot
async def send_embed(self, context: Context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
self, context: Context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -40,7 +44,9 @@ class Sync(commands.Cog, name="sync"):
description="Slash commands have been globally synchronized.", description="Slash commands have been globally synchronized.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
return return
elif scope == "guild": elif scope == "guild":
@@ -51,7 +57,9 @@ class Sync(commands.Cog, name="sync"):
description="Slash commands have been synchronized in this guild.", description="Slash commands have been synchronized in this guild.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
return return
embed = discord.Embed( embed = discord.Embed(
@@ -59,7 +67,9 @@ class Sync(commands.Cog, name="sync"):
description="The scope must be `global` or `guild`.", description="The scope must be `global` or `guild`.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
@commands.hybrid_command( @commands.hybrid_command(
@@ -87,7 +97,9 @@ class Sync(commands.Cog, name="sync"):
description="Slash commands have been globally unsynchronized.", description="Slash commands have been globally unsynchronized.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
return return
elif scope == "guild": elif scope == "guild":
@@ -98,7 +110,9 @@ class Sync(commands.Cog, name="sync"):
description="Slash commands have been unsynchronized in this guild.", description="Slash commands have been unsynchronized in this guild.",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed) await self.send_embed(context, embed)
return return
embed = discord.Embed( embed = discord.Embed(
@@ -106,10 +120,11 @@ class Sync(commands.Cog, name="sync"):
description="The scope must be `global` or `guild`.", description="The scope must be `global` or `guild`.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
async def cog_command_error(self, context: Context, error) -> None: async def cog_command_error(self, context: Context, error) -> None:
if isinstance(error, commands.NotOwner): if isinstance(error, commands.NotOwner):
embed = discord.Embed( embed = discord.Embed(
@@ -117,7 +132,9 @@ class Sync(commands.Cog, name="sync"):
description="You are not the owner of this bot!", description="You are not the owner of this bot!",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp") embed.set_author(
name="Owner", icon_url="https://yes.nighty.works/raw/zReOib.webp"
)
await self.send_embed(context, embed, ephemeral=True) await self.send_embed(context, embed, ephemeral=True)
else: else:
raise error raise error

View File

@@ -27,9 +27,12 @@ class Sidestore(commands.GroupCog, name="sidestore"):
embed = discord.Embed( embed = discord.Embed(
title="SideStore Commands", title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9 color=0x8E82F9,
)
embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot) view = SidestoreView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -38,9 +41,12 @@ class Sidestore(commands.GroupCog, name="sidestore"):
embed = discord.Embed( embed = discord.Embed(
title="SideStore Commands", title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9 color=0x8E82F9,
)
embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot) view = SidestoreView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -97,17 +103,17 @@ class Sidestore(commands.GroupCog, name="sidestore"):
async def sidestore_group_sparse(self, context: Context): async def sidestore_group_sparse(self, context: Context):
await self._invoke_hybrid(context, "sparse") await self._invoke_hybrid(context, "sparse")
@app_commands.command( @app_commands.command(name="help", description="SideStore troubleshooting help")
name="help",
description="SideStore troubleshooting help"
)
async def help(self, interaction: discord.Interaction): async def help(self, interaction: discord.Interaction):
embed = discord.Embed( embed = discord.Embed(
title="SideStore Commands", title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9 color=0x8E82F9,
)
embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot) view = SidestoreView(self.bot)
@@ -115,76 +121,66 @@ class Sidestore(commands.GroupCog, name="sidestore"):
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="refresh", name="refresh", description="Help with refreshing or installing apps"
description="Help with refreshing or installing apps"
) )
async def refresh(self, context): async def refresh(self, context):
return await refresh_command()(self, context) return await refresh_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="code", name="code", description="No code received when signing in with Apple ID"
description="No code received when signing in with Apple ID"
) )
async def code(self, context): async def code(self, context):
return await code_command()(self, context) return await code_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="crash", name="crash", description="Help with SideStore crashing issues"
description="Help with SideStore crashing issues"
) )
async def crash(self, context): async def crash(self, context):
return await crash_command()(self, context) return await crash_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="pairing", name="pairing", description="Help with pairing file issues"
description="Help with pairing file issues"
) )
async def pairing(self, context): async def pairing(self, context):
return await pairing_command()(self, context) return await pairing_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="server", name="server", description="Help with anisette server issues"
description="Help with anisette server issues"
) )
async def server(self, context): async def server(self, context):
return await server_command()(self, context) return await server_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="afc", name="afc", description="Help with AFC Connection Failure issues"
description="Help with AFC Connection Failure issues"
) )
async def afc(self, context): async def afc(self, context):
return await afc_command()(self, context) return await afc_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="udid", name="udid", description="SideStore could not determine device UDID"
description="SideStore could not determine device UDID"
) )
async def udid(self, context): async def udid(self, context):
return await udid_command()(self, context) return await udid_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(name="half", description="Help with half-installed apps")
name="half",
description="Help with half-installed apps"
)
async def half(self, context): async def half(self, context):
return await half_command()(self, context) return await half_command()(self, context)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="sparse", name="sparse", description="Help with sparse bundle issues"
description="Help with sparse bundle issues"
) )
async def sparse(self, context): async def sparse(self, context):
return await sparse_command()(self, context) return await sparse_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Sidestore(bot) cog = Sidestore(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -11,36 +11,42 @@ def afc_command():
) )
async def afc(self, context): async def afc(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# AFC Connection Failure\n\n---\n\n' + "# AFC Connection Failure\n\n---\n\n"
'1. Make sure Wi-Fi is connected to a stable network\n' + + "1. Make sure Wi-Fi is connected to a stable network\n"
'2. Make sure StosVPN is connected and updated\n' + + "2. Make sure StosVPN is connected and updated\n"
'3. If issue still persists, create and import a new pairing file using `idevice_pair`. See [Pairing File instructions](https://docs.sidestore.io/docs/installation/pairing-file) for details' + "3. If issue still persists, create and import a new pairing file using `idevice_pair`. See [Pairing File instructions](https://docs.sidestore.io/docs/installation/pairing-file) for details"
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/afc.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/afc.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/troubleshooting/common-issues#afc-connection-failure", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/common-issues#afc-connection-failure",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return afc return afc

View File

@@ -11,49 +11,53 @@ def code_command():
) )
async def code(self, context): async def code(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'## Verification Code Not Received When Signing In with Apple ID\n\n---\n\n' + "## Verification Code Not Received When Signing In with Apple ID\n\n---\n\n"
+ "1. **For iOS versions below 18.1:**\n"
'1. **For iOS versions below 18.1:**\n' + + ' - Open the "Settings" app\n'
' - Open the "Settings" app\n' + + " - Tap on your name at the top of the screen\n"
' - Tap on your name at the top of the screen\n' + + ' - Navigate to "Sign-In and Security"\n'
' - Navigate to "Sign-In and Security"\n' + + ' - Select "Two-Factor Authentication"\n'
' - Select "Two-Factor Authentication"\n' + + ' - Choose "Get Verification Code"\n\n'
' - Choose "Get Verification Code"\n\n' + + "2. **For iOS versions 18.1 and above:**\n"
'2. **For iOS versions 18.1 and above:**\n' + + " - Visit [iCloud](https://www.icloud.com) on a web browser\n"
' - Visit [iCloud](https://www.icloud.com) on a web browser\n' + + ' - Click "Sign In"\n'
' - Click "Sign In"\n' + + ' - On an Apple device, you may see two options: "Sign In" and "Use Different Apple Account"\n'
' - On an Apple device, you may see two options: "Sign In" and "Use Different Apple Account"\n' + + ' - Select the bottom option, "Use Different Apple Account"\n'
' - Select the bottom option, "Use Different Apple Account"\n' + + " - Enter your Apple ID and password, DO NOT USE A PASSKEY\n"
' - Enter your Apple ID and password, DO NOT USE A PASSKEY\n' + + " - Apple will send you a verification code\n"
' - Apple will send you a verification code\n' + + " - Use this code in SideStore to complete the sign-in process\n"
' - Use this code in SideStore to complete the sign-in process\n' ),
)
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/code.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/code.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/troubleshooting/#sign-in-issues", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/#sign-in-issues",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return code return code

View File

@@ -11,36 +11,39 @@ def crash_command():
) )
async def crash(self, context): async def crash(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# SideStore Crashing After Refresh\n\n---\n\n' + "# SideStore Crashing After Refresh\n\n---\n\n"
'First, to try and save your data:\n' + + "First, to try and save your data:\n"
"1. DON'T DELETE SIDESTORE, reinstall with AltServer's `Sideload .ipa`.\n" + + "1. DON'T DELETE SIDESTORE, reinstall with AltServer's `Sideload .ipa`.\n"
"If that doesn't work:\n" + + "If that doesn't work:\n"
+ "1. Delete your current SideStore. Reinstall with AltServer.\n"
'1. Delete your current SideStore. Reinstall with AltServer.\n' + + "2. Import your pairing file and sign into SideStore.\n"
'2. Import your pairing file and sign into SideStore.\n' + + "3. Download the SideStore .ipa file, and save it to your Files app.\n"
'3. Download the SideStore .ipa file, and save it to your Files app.\n' + + '4. Import the "Sidestore.ipa" file into SideStore, just like how you import any other IPA.\n\n'
'4. Import the "Sidestore.ipa" file into SideStore, just like how you import any other IPA.\n\n' + + "This process ensures SideStore is refreshed without issues."
'This process ensures SideStore is refreshed without issues.' ),
)
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/crash.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/crash.py",
)) emoji="<:githubicon:1417717356846776340>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return crash return crash

View File

@@ -11,42 +11,48 @@ def half_command():
) )
async def half(self, context): async def half(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# SideStore/IPAs Stuck Halfway Through Installing or Refreshing\n\n---\n' + "# SideStore/IPAs Stuck Halfway Through Installing or Refreshing\n\n---\n"
'- Make sure you are on the latest version of SideStore\n' + + "- Make sure you are on the latest version of SideStore\n"
'- Restart SideStore\n' + + "- Restart SideStore\n"
'- Restart device\n' + + "- Restart device\n"
'- Clear Cache\n' + + "- Clear Cache\n"
'- Change Anisette Server\n' + + "- Change Anisette Server\n"
'- Reset adi.pb\n' + + "- Reset adi.pb\n"
'- Sign out from SideStore and sign back in\n' + + "- Sign out from SideStore and sign back in\n"
'- Recreate pairing file\n' + + "- Recreate pairing file\n"
'- Reinstall SideStore\n\n' + "- Reinstall SideStore\n\n"
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/half.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/half.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/troubleshooting/common-issues#sidestore-hangs-halfway-through-installation", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/common-issues#sidestore-hangs-halfway-through-installation",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return half return half

View File

@@ -11,47 +11,53 @@ def pairing_command():
) )
async def pairing(self, context): async def pairing(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# Cannot Choose Pairing File\n\n---\n\n' + "# Cannot Choose Pairing File\n\n---\n\n"
'1. **Check File Extension:**\n' + + "1. **Check File Extension:**\n"
" Make sure your pairing file's extension ends with `.mobiledevicepairing` or `.plist`\n" + + " Make sure your pairing file's extension ends with `.mobiledevicepairing` or `.plist`\n"
' - If it doesn\'t, double-check to see if you had zipped your pairing file before sending it to your phone. Failing to do so may lead to the file being corrupted during transport\n\n' + + " - If it doesn't, double-check to see if you had zipped your pairing file before sending it to your phone. Failing to do so may lead to the file being corrupted during transport\n\n"
'2. **Move Pairing File:**\n' + + "2. **Move Pairing File:**\n"
' If you are unable to select the pairing file from within the app:\n' + + " If you are unable to select the pairing file from within the app:\n"
' - Rename the file to `ALTPairingFile.mobiledevicepairing`\n' + + " - Rename the file to `ALTPairingFile.mobiledevicepairing`\n"
' - Try moving the pairing file to the root directory of the SideStore folder in the Files app under "On My iPhone/iPad"\n\n' + + ' - Try moving the pairing file to the root directory of the SideStore folder in the Files app under "On My iPhone/iPad"\n\n'
'3. **Certificate Signing:**\n' + + "3. **Certificate Signing:**\n"
" When signing SideStore with certain certificates, you won't be able to select the pairing file from within the app\n" + + " When signing SideStore with certain certificates, you won't be able to select the pairing file from within the app\n"
' - Try the fix mentioned above\n' + + " - Try the fix mentioned above\n"
' - If you do not see the SideStore folder in the Files app:\n' + + " - If you do not see the SideStore folder in the Files app:\n"
' • Connect your phone to your computer\n' + + " • Connect your phone to your computer\n"
' • Drag and drop the pairing file into the SideStore app\'s files section\n' + + " • Drag and drop the pairing file into the SideStore app's files section\n"
' • Ensure the file is renamed to `ALTPairingFile.mobiledevicepairing`\n' + " • Ensure the file is renamed to `ALTPairingFile.mobiledevicepairing`\n"
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/pairing.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/pairing.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/troubleshooting/#cannot-choose-pairing-file", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/#cannot-choose-pairing-file",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return pairing return pairing

View File

@@ -11,37 +11,43 @@ def refresh_command():
) )
async def refresh(self, context): async def refresh(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# Can\'t Refresh or Install Apps\n\n---\n\n' + "# Can't Refresh or Install Apps\n\n---\n\n"
'1. Make sure your device is connected to a stable Wi-Fi network and not using cellular data.\n' + + "1. Make sure your device is connected to a stable Wi-Fi network and not using cellular data.\n"
'2. Verify VPN is connected in the StosVPN app.\n' + + "2. Verify VPN is connected in the StosVPN app.\n"
'3. **Create a brand new pairing file.**\n' + + "3. **Create a brand new pairing file.**\n"
' - If none of the above worked, it is very likely that the pairing file is corrupted. You can reference the documentation on how to create a new pairing file [here](https://docs.sidestore.io/docs/installation/pairing-file).\n' + " - If none of the above worked, it is very likely that the pairing file is corrupted. You can reference the documentation on how to create a new pairing file [here](https://docs.sidestore.io/docs/installation/pairing-file).\n"
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by neoarz') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/refresh.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/refresh.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/installation/pairing-file", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/installation/pairing-file",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return refresh return refresh

View File

@@ -11,41 +11,47 @@ def server_command():
) )
async def server(self, context): async def server(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# SideStore Freezing or Displaying an Error Code During Sign-In\n\n---\n\n' + "# SideStore Freezing or Displaying an Error Code During Sign-In\n\n---\n\n"
'1. **Change the Anisette Server:**\n' + + "1. **Change the Anisette Server:**\n"
' The most common solution is to switch to a different Anisette server. Do this:\n' + + " The most common solution is to switch to a different Anisette server. Do this:\n"
' - Open Sidestore settings\n' + + " - Open Sidestore settings\n"
' - Scroll down to the "Anisette Server" option\n' + + ' - Scroll down to the "Anisette Server" option\n'
' - Select a different server from the list\n' + + " - Select a different server from the list\n"
' - You might need to try a few servers from the list and find which works best for you\n\n' + + " - You might need to try a few servers from the list and find which works best for you\n\n"
'2. **Host Your Own Anisette Server:**\n' + + "2. **Host Your Own Anisette Server:**\n"
' If you prefer, you can set up your own Anisette server. Detailed instructions for hosting an Anisette server are available in the official documentation and can be found [here](https://docs.sidestore.io/docs/advanced/anisette).\n\n' + " If you prefer, you can set up your own Anisette server. Detailed instructions for hosting an Anisette server are available in the official documentation and can be found [here](https://docs.sidestore.io/docs/advanced/anisette).\n\n"
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/server.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/server.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/troubleshooting/#sidestore-freezing-or-displaying-an-error-code-during-sign-in", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/#sidestore-freezing-or-displaying-an-error-code-during-sign-in",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return server return server

View File

@@ -53,7 +53,7 @@ class SidestoreSelect(discord.ui.Select):
label="UDID Error", label="UDID Error",
value="udid", value="udid",
description="SideStore could not determine device UDID", description="SideStore could not determine device UDID",
) ),
] ]
super().__init__(placeholder="Choose a SideStore command...", options=options) super().__init__(placeholder="Choose a SideStore command...", options=options)
@@ -69,44 +69,60 @@ class SidestoreSelect(discord.ui.Select):
embed = discord.Embed( embed = discord.Embed(
title="Command Executed", title="Command Executed",
description=f"Successfully executed `/{command_name}`", description=f"Successfully executed `/{command_name}`",
color=0x00FF00 color=0x00FF00,
)
embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except discord.Forbidden: except discord.Forbidden:
guild_info = f"server {interaction.guild.name} (ID: {interaction.guild.id})" if interaction.guild else "DM or private channel" guild_info = (
self.bot.logger.warning(f"Bot missing permissions in {guild_info} - cannot execute {command_name} command") f"server {interaction.guild.name} (ID: {interaction.guild.id})"
if interaction.guild
else "DM or private channel"
)
self.bot.logger.warning(
f"Bot missing permissions in {guild_info} - cannot execute {command_name} command"
)
if interaction.guild is None: if interaction.guild is None:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="This command cannot be executed in DMs.", description="This command cannot be executed in DMs.",
color=0xFF0000 color=0xFF0000,
) )
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Permission Error", title="Permission Error",
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xFF0000 color=0xFF0000,
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
except Exception as e: except Exception as e:
self.bot.logger.error(f"Error executing {command_name} command: {e}") self.bot.logger.error(f"Error executing {command_name} command: {e}")
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="An error occurred while executing the command.", description="An error occurred while executing the command.",
color=0xFF0000 color=0xFF0000,
)
embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error", description="Command not found!", color=0xFF0000
description="Command not found!", )
color=0xFF0000 embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
await interaction.response.edit_message(embed=embed, view=None) await interaction.response.edit_message(embed=embed, view=None)
@@ -127,10 +143,15 @@ def sidestore_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -141,10 +162,15 @@ def sidestore_command():
description="The bot needs send messages permissions in this channel.", description="The bot needs send messages permissions in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, ephemeral=True) await context.interaction.response.send_message(
embed=embed, ephemeral=True
)
else: else:
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
return return
@@ -152,14 +178,19 @@ def sidestore_command():
embed = discord.Embed( embed = discord.Embed(
title="SideStore Commands", title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:", description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9 color=0x8E82F9,
)
embed.set_author(
name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot) view = SidestoreView(self.bot)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view, ephemeral=True) await context.interaction.response.send_message(
embed=embed, view=view, ephemeral=True
)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)

View File

@@ -11,36 +11,42 @@ def sparse_command():
) )
async def sparse(self, context): async def sparse(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# SparseRestore "Bypass 3 App Limit" Exploit\n\n---\n\n' + '# SparseRestore "Bypass 3 App Limit" Exploit\n\n---\n\n'
'The SparseRestore exploit allows you to bypass the 3-app sideloading limit. It is compatible with iOS/iPadOS versions **15.2 to 18.1 beta 4**, (not including **17.7.1** and **17.7.2**).\n\n' + + "The SparseRestore exploit allows you to bypass the 3-app sideloading limit. It is compatible with iOS/iPadOS versions **15.2 to 18.1 beta 4**, (not including **17.7.1** and **17.7.2**).\n\n"
'iOS/iPadOS versions **17.0** (not including **16.7** and **16.7.10**) are recommended to use [Trollstore](https://ios.cfw.guide/installing-trollstore/)\n\n' + + "iOS/iPadOS versions **17.0** (not including **16.7** and **16.7.10**) are recommended to use [Trollstore](https://ios.cfw.guide/installing-trollstore/)\n\n"
'If you\'re on a supported version and want to sideload more than three apps, follow the detailed instructions found in our documentation' + "If you're on a supported version and want to sideload more than three apps, follow the detailed instructions found in our documentation"
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by neoarz') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/sparse.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/sparse.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.primary, view.add_item(
url="https://docs.sidestore.io/docs/advanced/sparserestore", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/advanced/sparserestore",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return sparse return sparse

View File

@@ -11,35 +11,41 @@ def udid_command():
) )
async def udid(self, context): async def udid(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8E82F9,
description=( description=(
'# SideStore Could Not Determine Device UDID\n\n---\n\n' + "# SideStore Could Not Determine Device UDID\n\n---\n\n"
'This error usually occurs when the pairing file is corrupted. Please create a new pairing file using `idevice_pair` and try again.\n\n' + + "This error usually occurs when the pairing file is corrupted. Please create a new pairing file using `idevice_pair` and try again.\n\n"
'If you forgot how to create a new pairing file, you can refer to the documentation below.' + "If you forgot how to create a new pairing file, you can refer to the documentation below."
) ),
) )
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true") embed.set_author(
embed.set_footer(text=f'Last Edited by CelloSerenity') name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
)
embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
view.add_item(discord.ui.Button( view.add_item(
label="Edit Command", discord.ui.Button(
style=discord.ButtonStyle.secondary, label="Edit Command",
url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/udid.py", style=discord.ButtonStyle.secondary,
emoji="<:githubicon:1417717356846776340>" url="https://github.com/neoarz/Syntrel/blob/main/cogs/sidestore/udid.py",
)) emoji="<:githubicon:1417717356846776340>",
view.add_item(discord.ui.Button( )
label="Documentation", )
style=discord.ButtonStyle.secondary, view.add_item(
url="https://docs.sidestore.io/docs/installation/pairing-file/", discord.ui.Button(
emoji="<:sidestorepride:1417717648795631787>" label="Documentation",
)) style=discord.ButtonStyle.secondary,
url="https://docs.sidestore.io/docs/installation/pairing-file/",
emoji="<:sidestorepride:1417717648795631787>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return udid return udid

View File

@@ -20,10 +20,14 @@ class Utilities(commands.GroupCog, name="utils"):
embed = discord.Embed( embed = discord.Embed(
title="Utilities Commands", title="Utilities Commands",
description="Use `.utils <subcommand>` or `/utils <subcommand>`.", description="Use `.utils <subcommand>` or `/utils <subcommand>`.",
color=0x7289DA color=0x7289DA,
)
embed.set_author(
name="Utilities", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
embed.add_field(
name="Available", value="translate, codepreview, dictionary", inline=False
) )
embed.set_author(name="Utilities", icon_url="https://yes.nighty.works/raw/8VLDcg.webp")
embed.add_field(name="Available", value="translate, codepreview, dictionary", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
@@ -47,58 +51,64 @@ class Utilities(commands.GroupCog, name="utils"):
@app_commands.describe( @app_commands.describe(
text="The text to translate", text="The text to translate",
to_lang="Target language (e.g., 'en', 'es', 'fr')", to_lang="Target language (e.g., 'en', 'es', 'fr')",
from_lang="Source language (leave empty for auto-detect)" from_lang="Source language (leave empty for auto-detect)",
) )
@app_commands.autocomplete(to_lang=language_autocomplete) @app_commands.autocomplete(to_lang=language_autocomplete)
@app_commands.autocomplete(from_lang=language_autocomplete) @app_commands.autocomplete(from_lang=language_autocomplete)
async def utilities_group_translate(self, context: Context, text: str = None, to_lang: str = "en", from_lang: str = None): async def utilities_group_translate(
await self._invoke_hybrid(context, "translate", text=text, to_lang=to_lang, from_lang=from_lang) self,
context: Context,
text: str = None,
to_lang: str = "en",
from_lang: str = None,
):
await self._invoke_hybrid(
context, "translate", text=text, to_lang=to_lang, from_lang=from_lang
)
@utilities_group.command(name="codepreview") @utilities_group.command(name="codepreview")
async def utilities_group_codepreview(self, context: Context, url: str = None): async def utilities_group_codepreview(self, context: Context, url: str = None):
await self._invoke_hybrid(context, "codepreview", url=url) await self._invoke_hybrid(context, "codepreview", url=url)
@utilities_group.command(name="dictionary") @utilities_group.command(name="dictionary")
@app_commands.describe( @app_commands.describe(word="The word to look up")
word="The word to look up"
)
async def utilities_group_dictionary(self, context: Context, word: str = None): async def utilities_group_dictionary(self, context: Context, word: str = None):
await self._invoke_hybrid(context, "dictionary", word=word) await self._invoke_hybrid(context, "dictionary", word=word)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="translate", name="translate", description="Translate text to another language"
description="Translate text to another language"
) )
@app_commands.describe( @app_commands.describe(
text="The text to translate", text="The text to translate",
to_lang="Target language (e.g., 'en', 'es', 'fr')", to_lang="Target language (e.g., 'en', 'es', 'fr')",
from_lang="Source language (leave empty for auto-detect)" from_lang="Source language (leave empty for auto-detect)",
) )
@app_commands.autocomplete(to_lang=language_autocomplete) @app_commands.autocomplete(to_lang=language_autocomplete)
@app_commands.autocomplete(from_lang=language_autocomplete) @app_commands.autocomplete(from_lang=language_autocomplete)
async def translate(self, context, text: str = None, to_lang: str = "en", from_lang: str = None): async def translate(
return await translate_command()(self, context, text=text, to_lang=to_lang, from_lang=from_lang) self, context, text: str = None, to_lang: str = "en", from_lang: str = None
):
return await translate_command()(
self, context, text=text, to_lang=to_lang, from_lang=from_lang
)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="codepreview", name="codepreview", description="Preview code from GitHub URLs"
description="Preview code from GitHub URLs"
) )
async def codepreview(self, context, url: str = None): async def codepreview(self, context, url: str = None):
return await codepreview_command()(self, context, url=url) return await codepreview_command()(self, context, url=url)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="dictionary", name="dictionary", description="Get the definition of a word"
description="Get the definition of a word"
)
@app_commands.describe(
word="The word to look up"
) )
@app_commands.describe(word="The word to look up")
async def dictionary(self, context, word: str = None): async def dictionary(self, context, word: str = None):
return await dictionary_command()(self, context, word=word) return await dictionary_command()(self, context, word=word)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Utilities(bot) cog = Utilities(bot)
await bot.add_cog(cog) await bot.add_cog(cog)

View File

@@ -9,40 +9,44 @@ import json
def codepreview_command(): def codepreview_command():
LANGUAGE_MAP = { LANGUAGE_MAP = {
'.py': 'python', ".py": "python",
'.js': 'js', ".js": "js",
'.ts': 'ts', ".ts": "ts",
'.java': 'java', ".java": "java",
'.cpp': 'cpp', ".cpp": "cpp",
'.c': 'c', ".c": "c",
'.cs': 'cs', ".cs": "cs",
'.go': 'go', ".go": "go",
'.rs': 'rust', ".rs": "rust",
'.rb': 'ruby', ".rb": "ruby",
'.php': 'php', ".php": "php",
'.html': 'html', ".html": "html",
'.css': 'css', ".css": "css",
'.json': 'json', ".json": "json",
'.xml': 'xml', ".xml": "xml",
'.yaml': 'yaml', ".yaml": "yaml",
'.yml': 'yaml', ".yml": "yaml",
'.ini': 'ini', ".ini": "ini",
'.toml': 'toml', ".toml": "toml",
'.lua': 'lua', ".lua": "lua",
'.sh': 'bash', ".sh": "bash",
'.md': 'markdown', ".md": "markdown",
'.sql': 'sql', ".sql": "sql",
'.diff': 'diff', ".diff": "diff",
'.txt': '', ".txt": "",
} }
async def send_embed(context, embed: discord.Embed, *, ephemeral: bool = False) -> None: async def send_embed(
context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -50,7 +54,7 @@ def codepreview_command():
for ext, lang in LANGUAGE_MAP.items(): for ext, lang in LANGUAGE_MAP.items():
if filename.endswith(ext): if filename.endswith(ext):
return lang return lang
return '' return ""
async def fetch_github_content(url): async def fetch_github_content(url):
try: try:
@@ -64,10 +68,10 @@ def codepreview_command():
async def fetch_pr_diff(owner, repo, pr_number): async def fetch_pr_diff(owner, repo, pr_number):
try: try:
api_url = f'https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}' api_url = f"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}"
headers = { headers = {
'Accept': 'application/vnd.github.v3.diff', "Accept": "application/vnd.github.v3.diff",
'User-Agent': 'Discord-Bot' "User-Agent": "Discord-Bot",
} }
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
@@ -81,10 +85,10 @@ def codepreview_command():
async def fetch_pr_info(owner, repo, pr_number): async def fetch_pr_info(owner, repo, pr_number):
try: try:
api_url = f'https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}' api_url = f"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}"
headers = { headers = {
'Accept': 'application/vnd.github.v3+json', "Accept": "application/vnd.github.v3+json",
'User-Agent': 'Discord-Bot' "User-Agent": "Discord-Bot",
} }
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
@@ -92,87 +96,84 @@ def codepreview_command():
if response.status == 200: if response.status == 200:
pr_data = await response.json() pr_data = await response.json()
return { return {
'title': pr_data.get('title', ''), "title": pr_data.get("title", ""),
'number': pr_data.get('number', pr_number), "number": pr_data.get("number", pr_number),
'state': pr_data.get('state', ''), "state": pr_data.get("state", ""),
'merged': pr_data.get('merged', False), "merged": pr_data.get("merged", False),
'additions': pr_data.get('additions', 0), "additions": pr_data.get("additions", 0),
'deletions': pr_data.get('deletions', 0), "deletions": pr_data.get("deletions", 0),
'changed_files': pr_data.get('changed_files', 0), "changed_files": pr_data.get("changed_files", 0),
'user': pr_data.get('user', {}).get('login', ''), "user": pr_data.get("user", {}).get("login", ""),
'base_branch': pr_data.get('base', {}).get('ref', ''), "base_branch": pr_data.get("base", {}).get("ref", ""),
'head_branch': pr_data.get('head', {}).get('ref', '') "head_branch": pr_data.get("head", {}).get("ref", ""),
} }
except Exception: except Exception:
pass pass
return None return None
def parse_github_url(url): def parse_github_url(url):
pr_pattern = r'https://github\.com/([^/]+)/([^/]+)/pull/(\d+)(?:/files)?' pr_pattern = r"https://github\.com/([^/]+)/([^/]+)/pull/(\d+)(?:/files)?"
pr_match = re.match(pr_pattern, url) pr_match = re.match(pr_pattern, url)
if pr_match: if pr_match:
owner, repo, pr_number = pr_match.groups() owner, repo, pr_number = pr_match.groups()
return { return {"type": "pr", "owner": owner, "repo": repo, "pr_number": pr_number}
'type': 'pr',
'owner': owner,
'repo': repo,
'pr_number': pr_number
}
raw_pattern = r'https://raw\.githubusercontent\.com/([^/]+)/([^/]+)/([^/]+)/(.+?)$' raw_pattern = (
r"https://raw\.githubusercontent\.com/([^/]+)/([^/]+)/([^/]+)/(.+?)$"
)
raw_match = re.match(raw_pattern, url) raw_match = re.match(raw_pattern, url)
if raw_match: if raw_match:
owner, repo, branch, filepath = raw_match.groups() owner, repo, branch, filepath = raw_match.groups()
return { return {
'type': 'file', "type": "file",
'owner': owner, "owner": owner,
'repo': repo, "repo": repo,
'branch': branch, "branch": branch,
'filepath': filepath, "filepath": filepath,
'raw_url': url, "raw_url": url,
'start_line': None, "start_line": None,
'end_line': None "end_line": None,
} }
pattern = r'https://github\.com/([^/]+)/([^/]+)/blob/([^/]+)/(.+?)(?:#L(\d+)(?:-L(\d+))?)?$' pattern = r"https://github\.com/([^/]+)/([^/]+)/blob/([^/]+)/(.+?)(?:#L(\d+)(?:-L(\d+))?)?$"
match = re.match(pattern, url) match = re.match(pattern, url)
if match: if match:
owner, repo, branch, filepath, start_line, end_line = match.groups() owner, repo, branch, filepath, start_line, end_line = match.groups()
raw_url = f'https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{filepath}' raw_url = (
f"https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{filepath}"
)
return { return {
'type': 'file', "type": "file",
'owner': owner, "owner": owner,
'repo': repo, "repo": repo,
'branch': branch, "branch": branch,
'filepath': filepath, "filepath": filepath,
'raw_url': raw_url, "raw_url": raw_url,
'start_line': int(start_line) if start_line else None, "start_line": int(start_line) if start_line else None,
'end_line': int(end_line) if end_line else None "end_line": int(end_line) if end_line else None,
} }
return None return None
def extract_lines(content, start_line, end_line): def extract_lines(content, start_line, end_line):
lines = content.split('\n') lines = content.split("\n")
if start_line and end_line: if start_line and end_line:
return '\n'.join(lines[start_line-1:end_line]) return "\n".join(lines[start_line - 1 : end_line])
elif start_line: elif start_line:
return lines[start_line-1] if start_line <= len(lines) else content return lines[start_line - 1] if start_line <= len(lines) else content
return content return content
@commands.hybrid_command( @commands.hybrid_command(
name="codepreview", name="codepreview",
description="Preview code from GitHub URLs", description="Preview code from GitHub URLs",
) )
@app_commands.describe( @app_commands.describe(url="GitHub URL to preview code from")
url="GitHub URL to preview code from"
)
async def codepreview(self, context, url: str = None): async def codepreview(self, context, url: str = None):
if isinstance(context.channel, discord.DMChannel): if isinstance(context.channel, discord.DMChannel):
embed = discord.Embed( embed = discord.Embed(
@@ -180,7 +181,9 @@ def codepreview_command():
description="This command can only be used in servers.", description="This command can only be used in servers.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -198,7 +201,9 @@ def codepreview_command():
description="The bot needs the `send messages` permission in this channel.", description="The bot needs the `send messages` permission in this channel.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -211,10 +216,16 @@ def codepreview_command():
return return
if not url or not url.strip(): if not url or not url.strip():
if context.message and context.message.reference and context.message.reference.resolved: if (
context.message
and context.message.reference
and context.message.reference.resolved
):
replied_message = context.message.reference.resolved replied_message = context.message.reference.resolved
if hasattr(replied_message, 'content') and replied_message.content: if hasattr(replied_message, "content") and replied_message.content:
github_pattern = r'https://(?:github\.com|raw\.githubusercontent\.com)/[^\s]+' github_pattern = (
r"https://(?:github\.com|raw\.githubusercontent\.com)/[^\s]+"
)
urls = re.findall(github_pattern, replied_message.content) urls = re.findall(github_pattern, replied_message.content)
if urls: if urls:
url = urls[0] url = urls[0]
@@ -223,7 +234,10 @@ def codepreview_command():
title="Error", title="Error",
description="No GitHub URL found in the replied message.", description="No GitHub URL found in the replied message.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility",
icon_url="https://yes.nighty.works/raw/8VLDcg.webp",
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
else: else:
@@ -231,7 +245,10 @@ def codepreview_command():
title="Error", title="Error",
description="The replied message has no content to extract GitHub URL from.", description="The replied message has no content to extract GitHub URL from.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility",
icon_url="https://yes.nighty.works/raw/8VLDcg.webp",
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
else: else:
@@ -239,23 +256,31 @@ def codepreview_command():
title="Error", title="Error",
description="Please provide a GitHub URL or reply to a message containing a GitHub URL.", description="Please provide a GitHub URL or reply to a message containing a GitHub URL.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
if not url.startswith('https://github.com/') and not url.startswith('https://raw.githubusercontent.com/'): if not url.startswith("https://github.com/") and not url.startswith(
"https://raw.githubusercontent.com/"
):
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="Please provide a valid GitHub URL.", description="Please provide a valid GitHub URL.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
# Check if bot has send messages permission before starting processing # Check if bot has send messages permission before starting processing
try: try:
test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA) test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA)
test_embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") test_embed.set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await context.channel.send(embed=test_embed, delete_after=0.1) await context.channel.send(embed=test_embed, delete_after=0.1)
except discord.Forbidden: except discord.Forbidden:
embed = discord.Embed( embed = discord.Embed(
@@ -263,7 +288,9 @@ def codepreview_command():
description="The bot needs the `send messages` permission to execute this command.", description="The bot needs the `send messages` permission to execute this command.",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
@@ -282,29 +309,37 @@ def codepreview_command():
title="Error", title="Error",
description="Invalid GitHub URL format. Please provide a valid GitHub blob URL or PR URL.", description="Invalid GitHub URL format. Please provide a valid GitHub blob URL or PR URL.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
if parsed.get('type') == 'pr': if parsed.get("type") == "pr":
pr_info = await fetch_pr_info(parsed['owner'], parsed['repo'], parsed['pr_number']) pr_info = await fetch_pr_info(
diff_content = await fetch_pr_diff(parsed['owner'], parsed['repo'], parsed['pr_number']) parsed["owner"], parsed["repo"], parsed["pr_number"]
)
diff_content = await fetch_pr_diff(
parsed["owner"], parsed["repo"], parsed["pr_number"]
)
if not pr_info or not diff_content: if not pr_info or not diff_content:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="Failed to fetch pull request information. The PR might not exist or be accessible.", description="Failed to fetch pull request information. The PR might not exist or be accessible.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
pr_url = f"https://github.com/{parsed['owner']}/{parsed['repo']}/pull/{parsed['pr_number']}" pr_url = f"https://github.com/{parsed['owner']}/{parsed['repo']}/pull/{parsed['pr_number']}"
if pr_info['merged']: if pr_info["merged"]:
pr_color = 0x6f42c1 pr_color = 0x6F42C1
pr_status = "Merged" pr_status = "Merged"
elif pr_info['state'] == 'open': elif pr_info["state"] == "open":
pr_color = 0x57F287 pr_color = 0x57F287
pr_status = "Open" pr_status = "Open"
else: else:
@@ -316,11 +351,26 @@ def codepreview_command():
description=f"**Repository:** [{parsed['owner']}/{parsed['repo']}]({pr_url})\n**Author:** {pr_info['user']}\n**Status:** {pr_status}", description=f"**Repository:** [{parsed['owner']}/{parsed['repo']}]({pr_url})\n**Author:** {pr_info['user']}\n**Status:** {pr_status}",
color=pr_color, color=pr_color,
) )
embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
embed.add_field(name="Changes", value=f"**+{pr_info['additions']}** / **-{pr_info['deletions']}**", inline=True) name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
embed.add_field(name="Files Changed", value=f"{pr_info['changed_files']}", inline=True) )
embed.add_field(name="Branches", value=f"`{pr_info['base_branch']}` ← `{pr_info['head_branch']}`", inline=False) embed.add_field(
embed.set_footer(text=f"Requested by {context.author.name}", icon_url=context.author.display_avatar.url) name="Changes",
value=f"**+{pr_info['additions']}** / **-{pr_info['deletions']}**",
inline=True,
)
embed.add_field(
name="Files Changed", value=f"{pr_info['changed_files']}", inline=True
)
embed.add_field(
name="Branches",
value=f"`{pr_info['base_branch']}` ← `{pr_info['head_branch']}`",
inline=False,
)
embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None and not interaction.response.is_done(): if interaction is not None and not interaction.response.is_done():
@@ -331,29 +381,39 @@ def codepreview_command():
max_diff_length = 1900 max_diff_length = 1900
max_lines = 100 max_lines = 100
diff_lines = diff_content.split('\n') diff_lines = diff_content.split("\n")
if len(diff_lines) > max_lines: if len(diff_lines) > max_lines:
diff_lines = diff_lines[:max_lines] diff_lines = diff_lines[:max_lines]
diff_lines.append(f"\n... ({len(diff_content.split(chr(10))) - max_lines} more lines omitted)") diff_lines.append(
f"\n... ({len(diff_content.split(chr(10))) - max_lines} more lines omitted)"
)
current_chunk = "" current_chunk = ""
for line in diff_lines: for line in diff_lines:
test_chunk = current_chunk + line + '\n' test_chunk = current_chunk + line + "\n"
if len(test_chunk) + 10 > max_diff_length: if len(test_chunk) + 10 > max_diff_length:
if current_chunk.strip(): if current_chunk.strip():
remaining_lines = len(diff_lines) - len(current_chunk.split('\n')) remaining_lines = len(diff_lines) - len(
current_chunk.split("\n")
)
if remaining_lines > 0: if remaining_lines > 0:
current_chunk += f"\n... ({remaining_lines} more lines omitted)" current_chunk += (
await context.channel.send(f"```diff\n{current_chunk.rstrip()}\n```") f"\n... ({remaining_lines} more lines omitted)"
)
await context.channel.send(
f"```diff\n{current_chunk.rstrip()}\n```"
)
break break
else: else:
current_chunk = test_chunk current_chunk = test_chunk
else: else:
if current_chunk.strip(): if current_chunk.strip():
await context.channel.send(f"```diff\n{current_chunk.rstrip()}\n```") await context.channel.send(
f"```diff\n{current_chunk.rstrip()}\n```"
)
if interaction is not None: if interaction is not None:
try: try:
@@ -362,33 +422,35 @@ def codepreview_command():
pass pass
return return
content = await fetch_github_content(parsed['raw_url']) content = await fetch_github_content(parsed["raw_url"])
if not content: if not content:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="Failed to fetch content from GitHub. The file might not exist or be accessible.", description="Failed to fetch content from GitHub. The file might not exist or be accessible.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
if parsed['start_line']: if parsed["start_line"]:
code = extract_lines(content, parsed['start_line'], parsed['end_line']) code = extract_lines(content, parsed["start_line"], parsed["end_line"])
line_info = f" (Lines {parsed['start_line']}" line_info = f" (Lines {parsed['start_line']}"
if parsed['end_line']: if parsed["end_line"]:
line_info += f"-{parsed['end_line']}" line_info += f"-{parsed['end_line']}"
line_info += ")" line_info += ")"
else: else:
code = content code = content
line_info = "" line_info = ""
code_lines = code.split('\n') code_lines = code.split("\n")
if len(code_lines) > 100: if len(code_lines) > 100:
code = '\n'.join(code_lines[:100]) code = "\n".join(code_lines[:100])
code += f"\n\n... ({len(code_lines) - 100} more lines omitted)" code += f"\n\n... ({len(code_lines) - 100} more lines omitted)"
filename = parsed['filepath'].split('/')[-1] filename = parsed["filepath"].split("/")[-1]
language = get_language_from_filename(filename) language = get_language_from_filename(filename)
embed = discord.Embed( embed = discord.Embed(
@@ -396,10 +458,17 @@ def codepreview_command():
description=f"**Repository URL:** [{parsed['owner']}/{parsed['repo']}]({url})", description=f"**Repository URL:** [{parsed['owner']}/{parsed['repo']}]({url})",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
embed.add_field(name="File", value=f"`{parsed['filepath']}`{line_info}", inline=True) name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
embed.add_field(
name="File", value=f"`{parsed['filepath']}`{line_info}", inline=True
)
embed.add_field(name="Branch", value=f"`{parsed['branch']}`", inline=True) embed.add_field(name="Branch", value=f"`{parsed['branch']}`", inline=True)
embed.set_footer(text=f"Requested by {context.author.name}", icon_url=context.author.display_avatar.url) embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
code_block = f"```{language}\n{code}\n```" code_block = f"```{language}\n{code}\n```"
@@ -413,7 +482,7 @@ def codepreview_command():
await context.channel.send(embed=embed) await context.channel.send(embed=embed)
max_code_length = 1980 - len(language) - 8 max_code_length = 1980 - len(language) - 8
code_lines = code.split('\n') code_lines = code.split("\n")
current_chunk = [] current_chunk = []
current_length = 0 current_length = 0
@@ -422,8 +491,10 @@ def codepreview_command():
if current_length + line_length > max_code_length: if current_length + line_length > max_code_length:
remaining_lines = len(code_lines) - len(current_chunk) remaining_lines = len(code_lines) - len(current_chunk)
if remaining_lines > 0: if remaining_lines > 0:
current_chunk.append(f"\n... ({remaining_lines} more lines omitted)") current_chunk.append(
chunk_text = '\n'.join(current_chunk) f"\n... ({remaining_lines} more lines omitted)"
)
chunk_text = "\n".join(current_chunk)
await context.channel.send(f"```{language}\n{chunk_text}\n```") await context.channel.send(f"```{language}\n{chunk_text}\n```")
break break
else: else:
@@ -431,7 +502,7 @@ def codepreview_command():
current_length += line_length current_length += line_length
else: else:
if current_chunk: if current_chunk:
chunk_text = '\n'.join(current_chunk) chunk_text = "\n".join(current_chunk)
await context.channel.send(f"```{language}\n{chunk_text}\n```") await context.channel.send(f"```{language}\n{chunk_text}\n```")
if interaction is not None: if interaction is not None:

View File

@@ -6,14 +6,17 @@ import aiohttp
def dictionary_command(): def dictionary_command():
async def send_embed(
async def send_embed(context, embed: discord.Embed, *, ephemeral: bool = False) -> None: context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
@@ -29,7 +32,10 @@ def dictionary_command():
elif response.status == 404: elif response.status == 404:
return {"success": False, "error": "Word not found"} return {"success": False, "error": "Word not found"}
else: else:
return {"success": False, "error": f"API returned status code {response.status}"} return {
"success": False,
"error": f"API returned status code {response.status}",
}
except aiohttp.ClientError: except aiohttp.ClientError:
return {"success": False, "error": "Network error occurred"} return {"success": False, "error": "Network error occurred"}
except Exception as e: except Exception as e:
@@ -39,21 +45,26 @@ def dictionary_command():
name="dictionary", name="dictionary",
description="Get the definition of a word", description="Get the definition of a word",
) )
@app_commands.describe( @app_commands.describe(word="The word to look up")
word="The word to look up"
)
async def dictionary(self, context, word: str = None): async def dictionary(self, context, word: str = None):
if not word or not word.strip(): if not word or not word.strip():
if context.message and context.message.reference and context.message.reference.resolved: if (
context.message
and context.message.reference
and context.message.reference.resolved
):
replied_message = context.message.reference.resolved replied_message = context.message.reference.resolved
if hasattr(replied_message, 'content') and replied_message.content: if hasattr(replied_message, "content") and replied_message.content:
word = replied_message.content.strip().split()[0] word = replied_message.content.strip().split()[0]
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="The replied message has no text content to look up.", description="The replied message has no text content to look up.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility",
icon_url="https://yes.nighty.works/raw/8VLDcg.webp",
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
else: else:
@@ -61,7 +72,9 @@ def dictionary_command():
title="Error", title="Error",
description="Please provide a word to look up or reply to a message with a word.", description="Please provide a word to look up or reply to a message with a word.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -85,7 +98,9 @@ def dictionary_command():
title="Error", title="Error",
description=description, description=description,
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -96,7 +111,9 @@ def dictionary_command():
title="Error", title="Error",
description=f"No definition found for **{word}**.", description=f"No definition found for **{word}**.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -111,7 +128,9 @@ def dictionary_command():
description=f"**```{word_title}```**", description=f"**```{word_title}```**",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Utilities", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
name="Utilities", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
if phonetic: if phonetic:
embed.add_field(name="Pronunciation", value=f"`{phonetic}`", inline=False) embed.add_field(name="Pronunciation", value=f"`{phonetic}`", inline=False)
@@ -135,12 +154,20 @@ def dictionary_command():
examples.append(f"{def_idx}. {example}") examples.append(f"{def_idx}. {example}")
if def_text: if def_text:
field_name = f"{part_of_speech}" if part_of_speech else f"Definition {idx + 1}" field_name = (
embed.add_field(name=field_name, value=def_text.strip(), inline=False) f"{part_of_speech}"
if part_of_speech
else f"Definition {idx + 1}"
)
embed.add_field(
name=field_name, value=def_text.strip(), inline=False
)
if examples: if examples:
example_text = "\n".join(examples) example_text = "\n".join(examples)
embed.add_field(name="Examples", value=example_text, inline=False) embed.add_field(
name="Examples", value=example_text, inline=False
)
if idx < len(meanings[:max_meanings]) - 1: if idx < len(meanings[:max_meanings]) - 1:
embed.add_field(name="────────", value="", inline=False) embed.add_field(name="────────", value="", inline=False)
@@ -164,7 +191,6 @@ def dictionary_command():
antonym_text = ", ".join(antonyms[:10]) antonym_text = ", ".join(antonyms[:10])
embed.add_field(name="Antonyms", value=antonym_text, inline=True) embed.add_field(name="Antonyms", value=antonym_text, inline=True)
await send_embed(context, embed) await send_embed(context, embed)
return dictionary return dictionary

View File

@@ -10,130 +10,133 @@ import urllib.parse
languages = { languages = {
"auto": "Auto-detect", "auto": "Auto-detect",
"en": "English", "en": "English",
"es": "Spanish", "es": "Spanish",
"fr": "French", "fr": "French",
"de": "German", "de": "German",
"it": "Italian", "it": "Italian",
"pt": "Portuguese", "pt": "Portuguese",
"ru": "Russian", "ru": "Russian",
"ja": "Japanese", "ja": "Japanese",
"ko": "Korean", "ko": "Korean",
"zh-CN": "Chinese (Simplified)", "zh-CN": "Chinese (Simplified)",
"zh-TW": "Chinese (Traditional)", "zh-TW": "Chinese (Traditional)",
"ar": "Arabic", "ar": "Arabic",
"hi": "Hindi", "hi": "Hindi",
"th": "Thai", "th": "Thai",
"vi": "Vietnamese", "vi": "Vietnamese",
"nl": "Dutch", "nl": "Dutch",
"pl": "Polish", "pl": "Polish",
"tr": "Turkish", "tr": "Turkish",
"sv": "Swedish", "sv": "Swedish",
"da": "Danish", "da": "Danish",
"no": "Norwegian", "no": "Norwegian",
"fi": "Finnish", "fi": "Finnish",
"cs": "Czech", "cs": "Czech",
"sk": "Slovak", "sk": "Slovak",
"hu": "Hungarian", "hu": "Hungarian",
"ro": "Romanian", "ro": "Romanian",
"bg": "Bulgarian", "bg": "Bulgarian",
"hr": "Croatian", "hr": "Croatian",
"sr": "Serbian", "sr": "Serbian",
"sl": "Slovenian", "sl": "Slovenian",
"et": "Estonian", "et": "Estonian",
"lv": "Latvian", "lv": "Latvian",
"lt": "Lithuanian", "lt": "Lithuanian",
"uk": "Ukrainian", "uk": "Ukrainian",
"be": "Belarusian", "be": "Belarusian",
"mk": "Macedonian", "mk": "Macedonian",
"sq": "Albanian", "sq": "Albanian",
"mt": "Maltese", "mt": "Maltese",
"is": "Icelandic", "is": "Icelandic",
"ga": "Irish", "ga": "Irish",
"cy": "Welsh", "cy": "Welsh",
"gd": "Scots Gaelic", "gd": "Scots Gaelic",
"eu": "Basque", "eu": "Basque",
"ca": "Catalan", "ca": "Catalan",
"gl": "Galician", "gl": "Galician",
"eo": "Esperanto", "eo": "Esperanto",
"la": "Latin", "la": "Latin",
"af": "Afrikaans", "af": "Afrikaans",
"sw": "Swahili", "sw": "Swahili",
"zu": "Zulu", "zu": "Zulu",
"xh": "Xhosa", "xh": "Xhosa",
"yo": "Yoruba", "yo": "Yoruba",
"ig": "Igbo", "ig": "Igbo",
"ha": "Hausa", "ha": "Hausa",
"am": "Amharic", "am": "Amharic",
"om": "Oromo", "om": "Oromo",
"ti": "Tigrinya", "ti": "Tigrinya",
"so": "Somali", "so": "Somali",
"rw": "Kinyarwanda", "rw": "Kinyarwanda",
"lg": "Ganda", "lg": "Ganda",
"ny": "Chichewa", "ny": "Chichewa",
"sn": "Shona", "sn": "Shona",
"st": "Sesotho", "st": "Sesotho",
"tn": "Tswana", "tn": "Tswana",
"ts": "Tsonga", "ts": "Tsonga",
"ss": "Swati", "ss": "Swati",
"nr": "Ndebele", "nr": "Ndebele",
"nso": "Northern Sotho", "nso": "Northern Sotho",
"ve": "Venda", "ve": "Venda",
"bn": "Bengali", "bn": "Bengali",
"gu": "Gujarati", "gu": "Gujarati",
"kn": "Kannada", "kn": "Kannada",
"ml": "Malayalam", "ml": "Malayalam",
"mr": "Marathi", "mr": "Marathi",
"ne": "Nepali", "ne": "Nepali",
"or": "Odia", "or": "Odia",
"pa": "Punjabi", "pa": "Punjabi",
"si": "Sinhala", "si": "Sinhala",
"ta": "Tamil", "ta": "Tamil",
"te": "Telugu", "te": "Telugu",
"ur": "Urdu", "ur": "Urdu",
"as": "Assamese", "as": "Assamese",
"bho": "Bhojpuri", "bho": "Bhojpuri",
"doi": "Dogri", "doi": "Dogri",
"gom": "Konkani", "gom": "Konkani",
"mai": "Maithili", "mai": "Maithili",
"mni-Mtei": "Meiteilon", "mni-Mtei": "Meiteilon",
"sa": "Sanskrit", "sa": "Sanskrit",
"id": "Indonesian", "id": "Indonesian",
"ms": "Malay", "ms": "Malay",
"tl": "Filipino", "tl": "Filipino",
"jv": "Javanese", "jv": "Javanese",
"su": "Sundanese", "su": "Sundanese",
"ceb": "Cebuano", "ceb": "Cebuano",
"hil": "Hiligaynon", "hil": "Hiligaynon",
"ilo": "Iloko", "ilo": "Iloko",
"pam": "Kapampangan", "pam": "Kapampangan",
"war": "Waray", "war": "Waray",
"my": "Myanmar", "my": "Myanmar",
"km": "Khmer", "km": "Khmer",
"lo": "Lao", "lo": "Lao",
"ka": "Georgian", "ka": "Georgian",
"hy": "Armenian", "hy": "Armenian",
"az": "Azerbaijani", "az": "Azerbaijani",
"kk": "Kazakh", "kk": "Kazakh",
"ky": "Kyrgyz", "ky": "Kyrgyz",
"mn": "Mongolian", "mn": "Mongolian",
"tk": "Turkmen", "tk": "Turkmen",
"ug": "Uyghur", "ug": "Uyghur",
"uz": "Uzbek", "uz": "Uzbek",
"tg": "Tajik", "tg": "Tajik",
"fa": "Persian", "fa": "Persian",
"ps": "Pashto", "ps": "Pashto",
"sd": "Sindhi", "sd": "Sindhi",
"he": "Hebrew", "he": "Hebrew",
"yi": "Yiddish", "yi": "Yiddish",
"iw": "Hebrew", "iw": "Hebrew",
"el": "Greek", "el": "Greek",
"lt": "Lithuanian", "lt": "Lithuanian",
"lv": "Latvian", "lv": "Latvian",
} }
async def language_autocomplete(interaction: discord.Interaction, current: str) -> list[app_commands.Choice[str]]:
async def language_autocomplete(
interaction: discord.Interaction, current: str
) -> list[app_commands.Choice[str]]:
current = current.lower() current = current.lower()
choices = [] choices = []
@@ -155,19 +158,25 @@ async def language_autocomplete(interaction: discord.Interaction, current: str)
return choices return choices
def translate_command():
async def send_embed(context, embed: discord.Embed, *, ephemeral: bool = False) -> None: def translate_command():
async def send_embed(
context, embed: discord.Embed, *, ephemeral: bool = False
) -> None:
interaction = getattr(context, "interaction", None) interaction = getattr(context, "interaction", None)
if interaction is not None: if interaction is not None:
if interaction.response.is_done(): if interaction.response.is_done():
await interaction.followup.send(embed=embed, ephemeral=ephemeral) await interaction.followup.send(embed=embed, ephemeral=ephemeral)
else: else:
await interaction.response.send_message(embed=embed, ephemeral=ephemeral) await interaction.response.send_message(
embed=embed, ephemeral=ephemeral
)
else: else:
await context.send(embed=embed) await context.send(embed=embed)
async def _translate_with_google_web(text: str, from_lang: str = "auto", to_lang: str = "en") -> dict: async def _translate_with_google_web(
text: str, from_lang: str = "auto", to_lang: str = "en"
) -> dict:
try: try:
base_url = "https://translate.googleapis.com/translate_a/single" base_url = "https://translate.googleapis.com/translate_a/single"
@@ -208,9 +217,11 @@ def translate_command():
"sl": from_lang, "sl": from_lang,
"tl": to_lang, "tl": to_lang,
"dt": ["t", "bd"], "dt": ["t", "bd"],
"q": chunk "q": chunk,
} }
async with session.get(base_url, headers=headers, params=params) as response: async with session.get(
base_url, headers=headers, params=params
) as response:
if response.status != 200: if response.status != 200:
return None return None
result_text = (await response.text()).strip() result_text = (await response.text()).strip()
@@ -232,12 +243,11 @@ def translate_command():
return { return {
"translatedText": "".join(translated_parts).strip(), "translatedText": "".join(translated_parts).strip(),
"detectedSourceLanguage": detected_lang_overall "detectedSourceLanguage": detected_lang_overall,
} }
except Exception: except Exception:
return None return None
@commands.hybrid_command( @commands.hybrid_command(
name="translate", name="translate",
description="Translate text to another language", description="Translate text to another language",
@@ -245,22 +255,31 @@ def translate_command():
@app_commands.describe( @app_commands.describe(
text="The text to translate", text="The text to translate",
to_lang="Target language (e.g., 'en', 'es', 'fr')", to_lang="Target language (e.g., 'en', 'es', 'fr')",
from_lang="Source language (leave empty for auto-detect)" from_lang="Source language (leave empty for auto-detect)",
) )
@app_commands.autocomplete(to_lang=language_autocomplete) @app_commands.autocomplete(to_lang=language_autocomplete)
@app_commands.autocomplete(from_lang=language_autocomplete) @app_commands.autocomplete(from_lang=language_autocomplete)
async def translate(self, context, text: str = None, to_lang: str = "en", from_lang: str = None): async def translate(
self, context, text: str = None, to_lang: str = "en", from_lang: str = None
):
if not text or not text.strip(): if not text or not text.strip():
if context.message and context.message.reference and context.message.reference.resolved: if (
context.message
and context.message.reference
and context.message.reference.resolved
):
replied_message = context.message.reference.resolved replied_message = context.message.reference.resolved
if hasattr(replied_message, 'content') and replied_message.content: if hasattr(replied_message, "content") and replied_message.content:
text = replied_message.content text = replied_message.content
else: else:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="The replied message has no text content to translate.", description="The replied message has no text content to translate.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility",
icon_url="https://yes.nighty.works/raw/8VLDcg.webp",
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
else: else:
@@ -268,7 +287,9 @@ def translate_command():
title="Error", title="Error",
description="Please provide text to translate or reply to a message with text.", description="Please provide text to translate or reply to a message with text.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -277,7 +298,9 @@ def translate_command():
title="Error", title="Error",
description=f"Invalid target language code: `{to_lang}`. Use the autocomplete feature to see available languages.", description=f"Invalid target language code: `{to_lang}`. Use the autocomplete feature to see available languages.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -286,7 +309,9 @@ def translate_command():
title="Error", title="Error",
description=f"Invalid source language code: `{from_lang}`. Use the autocomplete feature to see available languages.", description=f"Invalid source language code: `{from_lang}`. Use the autocomplete feature to see available languages.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
@@ -303,7 +328,9 @@ def translate_command():
description=f"**Original:** {text}\n\n**Translated:** {result['translatedText']}", description=f"**Original:** {text}\n\n**Translated:** {result['translatedText']}",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") embed.set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
embed.set_footer(text=f"{from_lang_name} » {to_lang_name}") embed.set_footer(text=f"{from_lang_name} » {to_lang_name}")
await send_embed(context, embed) await send_embed(context, embed)
@@ -312,11 +339,9 @@ def translate_command():
title="Error", title="Error",
description="Translation failed. Please try again later.", description="Translation failed. Please try again later.",
color=0xE02B2B, color=0xE02B2B,
).set_author(name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp") ).set_author(
name="Utility", icon_url="https://yes.nighty.works/raw/8VLDcg.webp"
)
await send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return translate return translate

View File

@@ -7,3 +7,4 @@ Pillow
pillow-heif pillow-heif
pytz pytz
gTTS gTTS
ruff

View File

@@ -5,7 +5,13 @@ from .signal import setup_signal_handlers
from .contributors import generate_contributors_image from .contributors import generate_contributors_image
__all__ = [ __all__ = [
'ascii', 'ascii_plain', 'gradient_text', 'gradient_text_selective', "ascii",
'LoggingFormatter', 'setup_logger', 'get_uptime', 'setup_signal_handlers', "ascii_plain",
'generate_contributors_image' "gradient_text",
"gradient_text_selective",
"LoggingFormatter",
"setup_logger",
"get_uptime",
"setup_signal_handlers",
"generate_contributors_image",
] ]

View File

@@ -3,9 +3,11 @@
import math import math
def gradient_text(text, start_color, end_color): def gradient_text(text, start_color, end_color):
def rgb_interp(start, end, t): def rgb_interp(start, end, t):
return tuple(int(start[i] + (end[i] - start[i]) * t) for i in range(3)) return tuple(int(start[i] + (end[i] - start[i]) * t) for i in range(3))
lines = text.splitlines() lines = text.splitlines()
gradient_lines = [] gradient_lines = []
total_chars = sum(len(line) for line in lines if line.strip()) total_chars = sum(len(line) for line in lines if line.strip())
@@ -23,7 +25,10 @@ def gradient_text(text, start_color, end_color):
gradient_lines.append(colored_line) gradient_lines.append(colored_line)
return "\n".join(gradient_lines) return "\n".join(gradient_lines)
def gradient_text_selective(text, start_color, end_color, gradient_word, white_prefix=""):
def gradient_text_selective(
text, start_color, end_color, gradient_word, white_prefix=""
):
def rgb_interp(start, end, t): def rgb_interp(start, end, t):
return tuple(int(start[i] + (end[i] - start[i]) * t) for i in range(3)) return tuple(int(start[i] + (end[i] - start[i]) * t) for i in range(3))
@@ -39,7 +44,7 @@ def gradient_text_selective(text, start_color, end_color, gradient_word, white_p
before_prefix = line[:prefix_start] before_prefix = line[:prefix_start]
prefix_part = line[prefix_start:word_start] prefix_part = line[prefix_start:word_start]
word_part = gradient_word word_part = gradient_word
after_word = line[word_start + len(gradient_word):] after_word = line[word_start + len(gradient_word) :]
colored_before = "" colored_before = ""
total_chars = sum(1 for char in before_prefix if char.strip()) total_chars = sum(1 for char in before_prefix if char.strip())
@@ -65,7 +70,9 @@ def gradient_text_selective(text, start_color, end_color, gradient_word, white_p
else: else:
colored_word += char colored_word += char
result_lines.append(colored_before + white_prefix_colored + colored_word + after_word) result_lines.append(
colored_before + white_prefix_colored + colored_word + after_word
)
else: else:
colored_line = "" colored_line = ""
total_chars = sum(1 for char in line if char.strip()) total_chars = sum(1 for char in line if char.strip())

View File

@@ -1,15 +1,17 @@
import os import os
from discord.ext import commands from discord.ext import commands
def get_owner_friend_ids(): def get_owner_friend_ids():
owner_friends = os.getenv("OWNER_FRIENDS", "") owner_friends = os.getenv("OWNER_FRIENDS", "")
if not owner_friends.strip(): if not owner_friends.strip():
return [] return []
return [int(id.strip()) for id in owner_friends.split(",") if id.strip().isdigit()] return [int(id.strip()) for id in owner_friends.split(",") if id.strip().isdigit()]
def is_owner_or_friend(): def is_owner_or_friend():
async def predicate(ctx): async def predicate(ctx):
owner_friend_ids = get_owner_friend_ids() owner_friend_ids = get_owner_friend_ids()
return ctx.author.id in owner_friend_ids or await ctx.bot.is_owner(ctx.author) return ctx.author.id in owner_friend_ids or await ctx.bot.is_owner(ctx.author)
return commands.check(predicate)
return commands.check(predicate)

View File

@@ -15,7 +15,7 @@ def fetch_contributors(owner, repo):
headers = { headers = {
"User-Agent": "github-contributors-graph", "User-Agent": "github-contributors-graph",
"Accept": "application/vnd.github.v3+json" "Accept": "application/vnd.github.v3+json",
} }
response = requests.get(url, headers=headers, params=params) response = requests.get(url, headers=headers, params=params)
@@ -31,7 +31,7 @@ def fetch_contributors(owner, repo):
contributors.extend(data) contributors.extend(data)
page += 1 page += 1
if response.headers.get('X-RateLimit-Remaining') == '0': if response.headers.get("X-RateLimit-Remaining") == "0":
break break
return contributors return contributors
@@ -58,7 +58,9 @@ def download_avatar(avatar_url, size):
return None return None
def generate_contributors_image(owner="neoarz", repo="syntrel", size=64, images_per_row=20): def generate_contributors_image(
owner="neoarz", repo="syntrel", size=64, images_per_row=20
):
contributors = fetch_contributors(owner, repo) contributors = fetch_contributors(owner, repo)
if not contributors: if not contributors:
@@ -102,4 +104,3 @@ def generate_contributors_image(owner="neoarz", repo="syntrel", size=64, images_
buffer.seek(0) buffer.seek(0)
return buffer return buffer

View File

@@ -42,7 +42,9 @@ def setup_logger():
log_dir = os.path.dirname(log_file_path) log_dir = os.path.dirname(log_file_path)
if log_dir: if log_dir:
os.makedirs(log_dir, exist_ok=True) os.makedirs(log_dir, exist_ok=True)
file_handler = logging.FileHandler(filename=log_file_path, encoding="utf-8", mode="w") file_handler = logging.FileHandler(
filename=log_file_path, encoding="utf-8", mode="w"
)
file_handler_formatter = logging.Formatter( file_handler_formatter = logging.Formatter(
"[{asctime}] [{levelname:<8}] {name}: {message}", "%Y-%m-%d %H:%M:%S", style="{" "[{asctime}] [{levelname:<8}] {name}: {message}", "%Y-%m-%d %H:%M:%S", style="{"
) )