refactor(everything): combined all commands into command groups

This commit is contained in:
neo
2025-09-29 10:22:46 -04:00
committed by GitHub
47 changed files with 1092 additions and 517 deletions

44
bot.py
View File

@@ -86,21 +86,33 @@ class DiscordBot(commands.Bot):
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('__'):
for file in os.listdir(folder_path): init_file = os.path.join(folder_path, "__init__.py")
if file.endswith(".py") and not file.startswith('__'): if os.path.exists(init_file):
extension = file[:-3] try:
full_name = f"{folder}.{extension}".lower() await self.load_extension(f"cogs.{folder}")
if extension.lower() in disabled_cogs or full_name in disabled_cogs: if folder in ["owner", "help"]:
self.logger.info(f"Skipped disabled extension '{full_name}'") self.logger.info(f"Loaded extension '{folder}'")
continue except Exception as e:
try: exception = f"{type(e).__name__}: {e}"
await self.load_extension(f"cogs.{folder}.{extension}") self.logger.error(
self.logger.info(f"Loaded extension '{folder}.{extension}'") f"Failed to load extension {folder}\n{exception}"
except Exception as e: )
exception = f"{type(e).__name__}: {e}" else:
self.logger.error( for file in os.listdir(folder_path):
f"Failed to load extension {folder}.{extension}\n{exception}" if file.endswith(".py") and not file.startswith('__'):
) extension = file[:-3]
full_name = f"{folder}.{extension}".lower()
if extension.lower() in disabled_cogs or full_name in disabled_cogs:
self.logger.info(f"Skipped disabled extension '{full_name}'")
continue
try:
await self.load_extension(f"cogs.{folder}.{extension}")
self.logger.info(f"Loaded extension '{folder}.{extension}'")
except Exception as e:
exception = f"{type(e).__name__}: {e}"
self.logger.error(
f"Failed to load extension {folder}.{extension}\n{exception}"
)
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('__'):
@@ -271,6 +283,8 @@ class DiscordBot(commands.Bot):
color=0xE02B2B, color=0xE02B2B,
) )
await context.send(embed=embed) await context.send(embed=embed)
elif isinstance(error, commands.CheckFailure):
return
else: else:
raise error raise error

108
cogs/fun/__init__.py Normal file
View File

@@ -0,0 +1,108 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
from .coinflip import coinflip_command
from .eightball import eightball_command
from .minesweeper import minesweeper_command
from .randomfact import randomfact_command
from .rockpaperscissors import rps_command
class Fun(commands.GroupCog, name="fun"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="fun", invoke_without_command=True)
async def fun_group(self, context: Context):
embed = discord.Embed(
title="Fun Commands",
description="Use `.fun <subcommand>` or slash `/fun <subcommand>`.",
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)
await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command, **kwargs)
else:
await context.send(f"Unknown fun command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@fun_group.command(name="coinflip")
async def fun_group_coinflip(self, context: Context):
await self._invoke_hybrid(context, "coinflip")
@fun_group.command(name="8ball")
async def fun_group_8ball(self, context: Context, *, question: str):
await self._invoke_hybrid(context, "8ball", question=question)
@fun_group.command(name="minesweeper")
async def fun_group_minesweeper(self, context: Context):
await self._invoke_hybrid(context, "minesweeper")
@fun_group.command(name="randomfact")
async def fun_group_randomfact(self, context: Context):
await self._invoke_hybrid(context, "randomfact")
@fun_group.command(name="rps")
async def fun_group_rps(self, context: Context):
await self._invoke_hybrid(context, "rps")
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="coinflip",
description="Make a coin flip, but give your bet before."
)
async def coinflip(self, context):
return await coinflip_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="8ball",
description="Ask any question to the bot.",
)
async def eight_ball(self, context, *, question: str):
return await eightball_command()(self, context, question=question)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="minesweeper",
description="Play a buttoned minesweeper mini-game."
)
async def minesweeper(self, context):
return await minesweeper_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(name="randomfact", description="Get a random fact.")
async def randomfact(self, context):
return await randomfact_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="rps", description="Play the rock paper scissors game against the bot."
)
async def rock_paper_scissors(self, context):
return await rps_command()(self, context)
async def setup(bot) -> None:
cog = Fun(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'fun.coinflip'")
bot.logger.info("Loaded extension 'fun.8ball'")
bot.logger.info("Loaded extension 'fun.minesweeper'")
bot.logger.info("Loaded extension 'fun.randomfact'")
bot.logger.info("Loaded extension 'fun.rps'")

View File

@@ -1,7 +1,6 @@
import random import random
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class Choice(discord.ui.View): class Choice(discord.ui.View):
def __init__(self) -> None: def __init__(self) -> None:
@@ -22,18 +21,12 @@ class Choice(discord.ui.View):
self.value = "tails" self.value = "tails"
self.stop() self.stop()
class CoinFlip(commands.Cog, name="coinflip"): def coinflip_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="coinflip", description="Make a coin flip, but give your bet before." name="coinflip",
description="Make a coin flip, but give your bet before."
) )
async def coinflip(self, context: Context) -> None: async def coinflip(self, context):
"""
Make a coin flip, but give your bet before.
:param context: The hybrid command context.
"""
buttons = Choice() buttons = Choice()
embed = discord.Embed( embed = discord.Embed(
title="Coinflip", title="Coinflip",
@@ -60,5 +53,4 @@ class CoinFlip(commands.Cog, name="coinflip"):
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)
async def setup(bot) -> None: return coinflip
await bot.add_cog(CoinFlip(bot))

View File

@@ -1,26 +1,12 @@
import random import random
import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class EightBall(commands.Cog, name="8ball"):
def __init__(self, bot) -> None:
self.bot = bot
def eightball_command():
@commands.hybrid_command( @commands.hybrid_command(
name="8ball", name="8ball",
description="Ask any question to the bot.", description="Ask any question to the bot.",
) )
@app_commands.describe(question="The question you want to ask.") async def eight_ball(self, context, *, question: str):
async def eight_ball(self, context: Context, *, question: str) -> None:
"""
Ask any question to the bot.
:param context: The hybrid command context.
:param question: The question that should be asked by the user.
"""
answers = [ answers = [
"It is certain.", "It is certain.",
"It is decidedly so.", "It is decidedly so.",
@@ -52,6 +38,4 @@ class EightBall(commands.Cog, name="8ball"):
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)
return eight_ball
async def setup(bot) -> None:
await bot.add_cog(EightBall(bot))

View File

@@ -2,8 +2,6 @@ import random
from itertools import repeat from itertools import repeat
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
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):
@@ -66,7 +64,6 @@ class RowButton(discord.ui.Button):
await interaction.edit_original_response(view=view) await interaction.edit_original_response(view=view)
class MsView(discord.ui.View): class MsView(discord.ui.View):
def __init__(self, ctx, options, bombs, board): def __init__(self, ctx, options, bombs, board):
super().__init__() super().__init__()
@@ -155,21 +152,13 @@ class MsView(discord.ui.View):
self.GetBoardPos(pos) self.GetBoardPos(pos)
] = bombemo ] = bombemo
def minesweeper_command():
class Minesweeper(commands.Cog, name="minesweeper"):
def __init__(self, bot) -> None:
self.bot = bot
@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: Context) -> None: async def minesweeper(self, context):
""" board = [[" "] * 5 for _ in range(5)]
Play a buttoned minesweeper mini-game.
:param context: The hybrid command context.
"""
board = [[" "] * 5 for _ in range(5)] # Unicode block character, usually doesnt show up in Discord or github, search up invisible character on google
bombs = 0 bombs = 0
bombpositions = [] bombpositions = []
for x in repeat(None, random.randint(4, 11)): for x in repeat(None, random.randint(4, 11)):
@@ -198,6 +187,4 @@ class Minesweeper(commands.Cog, name="minesweeper"):
message = await context.send(embed=embed, view=view) message = await context.send(embed=embed, view=view)
view.message = message view.message = message
return minesweeper
async def setup(bot) -> None:
await bot.add_cog(Minesweeper(bot))

View File

@@ -1,15 +1,10 @@
import aiohttp import aiohttp
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class RandomFact(commands.Cog, name="randomfact"):
def __init__(self, bot) -> None:
self.bot = bot
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: Context) -> None: async def randomfact(self, context):
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
"https://uselessfacts.jsph.pl/random.json?language=en" "https://uselessfacts.jsph.pl/random.json?language=en"
@@ -31,6 +26,4 @@ class RandomFact(commands.Cog, name="randomfact"):
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
async def setup(bot) -> None:
await bot.add_cog(RandomFact(bot))

View File

@@ -1,7 +1,6 @@
import random import random
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class RockPaperScissors(discord.ui.Select): class RockPaperScissors(discord.ui.Select):
def __init__(self) -> None: def __init__(self) -> None:
@@ -39,7 +38,6 @@ class RockPaperScissors(discord.ui.Select):
winner = (3 + user_choice_index - bot_choice_index) % 3 winner = (3 + user_choice_index - bot_choice_index) % 3
# Get the user mention
user_mention = interaction.user.mention user_mention = interaction.user.mention
if winner == 0: if winner == 0:
@@ -61,14 +59,11 @@ class RockPaperScissorsView(discord.ui.View):
super().__init__() super().__init__()
self.add_item(RockPaperScissors()) self.add_item(RockPaperScissors())
class RPS(commands.Cog, name="rps"): def rps_command():
def __init__(self, bot) -> None:
self.bot = bot
@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."
) )
async def rock_paper_scissors(self, context: Context) -> None: async def rock_paper_scissors(self, context):
view = RockPaperScissorsView() view = RockPaperScissorsView()
embed = discord.Embed( embed = discord.Embed(
title="Rock Paper Scissors", title="Rock Paper Scissors",
@@ -78,5 +73,4 @@ class RPS(commands.Cog, name="rps"):
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)
async def setup(bot) -> None: return rock_paper_scissors
await bot.add_cog(RPS(bot))

113
cogs/general/__init__.py Normal file
View File

@@ -0,0 +1,113 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
from .ping import ping_command
from .uptime import uptime_command
from .botinfo import botinfo_command
from .serverinfo import serverinfo_command
from .feedback import feedback_command
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
class General(commands.GroupCog, name="general"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="general", invoke_without_command=True)
async def general_group(self, context: Context):
embed = discord.Embed(
title="General Commands",
description="Use `.general <subcommand>` or `/general <subcommand>`.",
color=0x7289DA
)
embed.set_author(name="General", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
embed.add_field(name="Available", value="ping, uptime, botinfo, serverinfo, feedback", inline=False)
await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command)
else:
await context.send(f"Unknown general command: {name}")
@general_group.command(name="ping")
async def general_group_ping(self, context: Context):
await self._invoke_hybrid(context, "ping")
@general_group.command(name="uptime")
async def general_group_uptime(self, context: Context):
await self._invoke_hybrid(context, "uptime")
@general_group.command(name="botinfo")
async def general_group_botinfo(self, context: Context):
await self._invoke_hybrid(context, "botinfo")
@general_group.command(name="serverinfo")
async def general_group_serverinfo(self, context: Context):
await self._invoke_hybrid(context, "serverinfo")
@general_group.command(name="feedback")
async def general_group_feedback(self, context: Context):
await self._invoke_hybrid(context, "feedback")
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="ping",
description="Check if the bot is alive.",
)
async def ping(self, context):
return await ping_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="uptime",
description="Check how long the bot has been running.",
)
async def uptime(self, context):
return await uptime_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="botinfo",
description="Get some useful (or not) information about the bot.",
)
async def botinfo(self, context):
return await botinfo_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="serverinfo",
description="Get some useful (or not) information about the server.",
)
async def serverinfo(self, context):
return await serverinfo_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="feedback",
description="Submit a feedback for the owners of the bot"
)
async def feedback(self, context):
return await feedback_command()(self, context)
async def setup(bot) -> None:
cog = General(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'general.ping'")
bot.logger.info("Loaded extension 'general.uptime'")
bot.logger.info("Loaded extension 'general.botinfo'")
bot.logger.info("Loaded extension 'general.serverinfo'")
bot.logger.info("Loaded extension 'general.feedback'")

View File

@@ -1,23 +1,13 @@
import platform import platform
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class BotInfo(commands.Cog, name="botinfo"):
def __init__(self, bot) -> None:
self.bot = bot
def botinfo_command():
@commands.hybrid_command( @commands.hybrid_command(
name="botinfo", name="botinfo",
description="Get some useful (or not) information about the bot.", description="Get some useful (or not) information about the bot.",
) )
async def botinfo(self, context: Context) -> None: async def botinfo(self, context):
"""
Get some useful (or not) information about the bot.
:param context: The hybrid command context.
"""
embed = discord.Embed( embed = discord.Embed(
title="Syntrel Discord Bot", title="Syntrel Discord Bot",
color=0x7289DA, color=0x7289DA,
@@ -37,5 +27,4 @@ class BotInfo(commands.Cog, name="botinfo"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
async def setup(bot) -> None: return botinfo
await bot.add_cog(BotInfo(bot))

View File

@@ -2,7 +2,6 @@ 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?",
@@ -17,20 +16,11 @@ class FeedbackForm(discord.ui.Modal, title="Feeedback"):
self.answer = str(self.feedback) self.answer = str(self.feedback)
self.stop() self.stop()
def feedback_command():
class Feedback(commands.Cog, name="feedback"):
def __init__(self, bot) -> None:
self.bot = bot
@app_commands.command( @app_commands.command(
name="feedback", description="Submit a feedback for the owners of the bot" name="feedback", description="Submit a feedback for the owners of the bot"
) )
async def feedback(self, interaction: discord.Interaction) -> None: async def feedback(self, interaction: discord.Interaction):
"""
Submit a feedback for the owners of the bot.
:param interaction: The application command interaction.
"""
feedback_form = FeedbackForm() feedback_form = FeedbackForm()
await interaction.response.send_modal(feedback_form) await interaction.response.send_modal(feedback_form)
@@ -54,6 +44,4 @@ class Feedback(commands.Cog, name="feedback"):
).set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") ).set_author(name="Feedback System", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
) )
return feedback
async def setup(bot) -> None:
await bot.add_cog(Feedback(bot))

View File

@@ -1,22 +1,12 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class Ping(commands.Cog, name="ping"):
def __init__(self, bot) -> None:
self.bot = bot
def ping_command():
@commands.hybrid_command( @commands.hybrid_command(
name="ping", name="ping",
description="Check if the bot is alive.", description="Check if the bot is alive.",
) )
async def ping(self, context: Context) -> None: async def ping(self, context):
"""
Check if the bot is alive.
:param context: The hybrid command context.
"""
embed = discord.Embed( embed = discord.Embed(
title="🏓 Pong!", title="🏓 Pong!",
description=f"The bot latency is {round(self.bot.latency * 1000)}ms.", description=f"The bot latency is {round(self.bot.latency * 1000)}ms.",
@@ -32,6 +22,4 @@ class Ping(commands.Cog, name="ping"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
return ping
async def setup(bot) -> None:
await bot.add_cog(Ping(bot))

View File

@@ -1,22 +1,13 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class ServerInfo(commands.Cog, name="serverinfo"):
def __init__(self, bot) -> None:
self.bot = bot
def serverinfo_command():
@commands.hybrid_command( @commands.hybrid_command(
name="serverinfo", name="serverinfo",
description="Get some useful (or not) information about the server.", description="Get some useful (or not) information about the server.",
) )
@commands.guild_only() # This decorator ensures the command only works in servers @commands.guild_only()
async def serverinfo(self, context: Context) -> None: async def serverinfo(self, context):
"""
Get some useful (or not) information about the server.
:param context: The hybrid command context.
"""
# Additional check (though @commands.guild_only() should handle this)
if context.guild is None: if context.guild is None:
await context.send("This command can only be used in a server, not in DMs!") await context.send("This command can only be used in a server, not in DMs!")
return return
@@ -54,5 +45,4 @@ class ServerInfo(commands.Cog, name="serverinfo"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
async def setup(bot) -> None: return serverinfo
await bot.add_cog(ServerInfo(bot))

View File

@@ -1,7 +1,5 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
class UptimeView(discord.ui.View): class UptimeView(discord.ui.View):
def __init__(self, bot): def __init__(self, bot):
@@ -18,21 +16,12 @@ class UptimeView(discord.ui.View):
embed.set_author(name="Uptime", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp") embed.set_author(name="Uptime", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp")
await interaction.response.edit_message(embed=embed, view=self) await interaction.response.edit_message(embed=embed, view=self)
def uptime_command():
class Uptime(commands.Cog, name="uptime"):
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="uptime", name="uptime",
description="Check how long the bot has been running.", description="Check how long the bot has been running.",
) )
async def uptime(self, context: Context) -> None: async def uptime(self, context):
"""
Check how long the bot has been running.
:param context: The hybrid command context.
"""
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()}**",
@@ -49,6 +38,4 @@ class Uptime(commands.Cog, name="uptime"):
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return uptime
async def setup(bot) -> None:
await bot.add_cog(Uptime(bot))

View File

@@ -37,67 +37,22 @@ class Help(commands.Cog, name="help"):
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 Commands "general": "general",
"help": "general", "fun": "fun",
"botinfo": "general",
"serverinfo": "general",
"ping": "general",
"feedback": "general",
"uptime": "general",
# "context_menus": "general",
# Fun Commands
"randomfact": "fun",
"coinflip": "fun",
"rps": "fun",
"8ball": "fun",
"minesweeper": "fun",
# Moderation Commands
"kick": "moderation",
"ban": "moderation",
"nick": "moderation",
"purge": "moderation",
"hackban": "moderation",
"warnings": "moderation",
"archive": "moderation",
# SideStore Commands
"sidestore": "sidestore",
"refresh": "sidestore",
"code": "sidestore",
"crash": "sidestore",
"pairing": "sidestore",
"server": "sidestore",
"half": "sidestore",
"sparse": "sidestore",
"afc": "sidestore",
"udid": "sidestore",
# idevice Commands
"idevice": "idevice", "idevice": "idevice",
"noapps": "idevice", "miscellaneous": "miscellaneous",
"errorcodes": "idevice", "moderation": "moderation",
"developermode": "idevice", "sidestore": "sidestore",
"mountddi": "idevice", "utilities": "utilities",
# Owner Commands
"sync": "owner", "sync": "owner",
"cog_management": "owner", "logs": "owner",
"invite": "owner",
"load": "owner",
"unload": "owner",
"reload": "owner",
"shutdown": "owner", "shutdown": "owner",
"say": "owner", "say": "owner",
"invite": "owner",
"logs": "owner",
# Utilities Commands
"translate": "utilities",
# Miscellaneous Commands
"keanu": "miscellaneous",
"labubu": "miscellaneous",
"piracy": "miscellaneous",
"tryitandsee": "miscellaneous",
"rr": "miscellaneous",
} }
category_descriptions = { category_descriptions = {
@@ -184,6 +139,14 @@ class Help(commands.Cog, name="help"):
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)
if hasattr(app_command, 'commands') and category not in ["owner"]:
for subcommand in app_command.commands:
if subcommand.name in seen_names:
continue
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}")
if not commands_in_category: if not commands_in_category:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",

126
cogs/idevice/__init__.py Normal file
View File

@@ -0,0 +1,126 @@
import discord
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import Context
from .idevice import ideviceView
from .error_codes import errorcodes_command
from .developermode import developermode_command
from .noapps import noapps_command
from .mountddi import mountddi_command
class Idevice(commands.GroupCog, name="idevice"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="idevice", invoke_without_command=True)
async def idevice_group(self, context: Context):
embed = discord.Embed(
title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a
)
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot)
await context.send(embed=embed, view=view)
@idevice_group.command(name="help")
async def idevice_group_help(self, context: Context):
embed = discord.Embed(
title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a
)
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot)
await context.send(embed=embed, view=view)
async def _invoke_hybrid(self, context: Context, name: str):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command)
else:
await context.send(f"Unknown idevice command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@idevice_group.command(name="errorcodes")
async def idevice_group_errorcodes(self, context: Context):
await self._invoke_hybrid(context, "errorcodes")
@idevice_group.command(name="developermode")
async def idevice_group_developermode(self, context: Context):
await self._invoke_hybrid(context, "developermode")
@idevice_group.command(name="noapps")
async def idevice_group_noapps(self, context: Context):
await self._invoke_hybrid(context, "noapps")
@idevice_group.command(name="mountddi")
async def idevice_group_mountddi(self, context: Context):
await self._invoke_hybrid(context, "mountddi")
@app_commands.command(
name="help",
description="idevice troubleshooting help"
)
async def help(self, interaction: discord.Interaction):
embed = discord.Embed(
title="idevice Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0xfa8c4a
)
embed.set_author(name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png")
view = ideviceView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="errorcodes",
description="Look up error codes and their meanings."
)
async def errorcodes(self, context, *, error_code: str = None):
return await errorcodes_command()(self, context, error_code=error_code)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="developermode",
description="How to turn on developer mode"
)
async def developermode(self, context):
return await developermode_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="noapps",
description="Help when apps aren't showing in installed apps view"
)
async def noapps(self, context):
return await noapps_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="mountddi",
description="How to manually mount DDI"
)
async def mountddi(self, context):
return await mountddi_command()(self, context)
async def setup(bot) -> None:
cog = Idevice(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'idevice.help'")
bot.logger.info("Loaded extension 'idevice.errorcodes'")
bot.logger.info("Loaded extension 'idevice.developermode'")
bot.logger.info("Loaded extension 'idevice.noapps'")
bot.logger.info("Loaded extension 'idevice.mountddi'")

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Developermode(commands.Cog, name="developermode"): def developermode_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="developermode", description="How to turn on developer mode" name="developermode", description="How to turn on developer mode"
) )
async def developermode(self, context: Context) -> None: async def developermode(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0xfa8c4a, color=0xfa8c4a,
description=( description=(
@@ -41,6 +38,4 @@ class Developermode(commands.Cog, name="developermode"):
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return developermode
async def setup(bot) -> None:
await bot.add_cog(Developermode(bot))

View File

@@ -6,54 +6,41 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class ErrorCodes(commands.Cog, name="errorcodes"): def errorcodes_command():
def __init__(self, bot) -> None: @commands.hybrid_command(name="errorcodes", description="Look up an idevice error code by name or number")
self.bot = bot
self.errors = self.load_errors()
self.key_to_data = {error['name']: (error['description'], error['code']) for error in self.errors}
self.code_to_key = {error['code']: error['name'] for error in self.errors}
def load_errors(self):
json_path = os.path.join(os.path.dirname(__file__), 'files/errorcodes.json')
try:
with open(json_path, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
self.bot.logger.error(f"Error codes JSON file not found: {json_path}")
return []
except json.JSONDecodeError as e:
self.bot.logger.error(f"Error parsing error codes JSON: {e}")
return []
async def errorcode_autocomplete(self, interaction: discord.Interaction, current: str):
current_lower = current.lower()
items = []
for key, (title, code) in self.key_to_data.items():
if not current or current_lower in key.lower() or current_lower in title.lower() or current_lower in str(code):
items.append(app_commands.Choice(name=f"{key} » {title} ({code})", value=key))
if len(items) >= 25:
break
return items
@commands.hybrid_command(name="errorcode", 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")
@app_commands.autocomplete(name=errorcode_autocomplete) async def errorcodes(self, context, name: str):
async def errorcode(self, context: Context, name: str): def load_errors():
json_path = os.path.join(os.path.dirname(__file__), 'files/errorcodes.json')
try:
with open(json_path, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
self.bot.logger.error(f"Error codes JSON file not found: {json_path}")
return []
except json.JSONDecodeError as e:
self.bot.logger.error(f"Error parsing error codes JSON: {e}")
return []
errors = load_errors()
key_to_data = {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 self.key_to_data: if key not in key_to_data:
try: try:
num = int(name) num = int(name)
key = self.code_to_key.get(num) key = code_to_key.get(num)
except ValueError: except ValueError:
key = None key = None
if key is None or key not in self.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
title, code = self.key_to_data[key] title, code = key_to_data[key]
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}",
@@ -74,8 +61,6 @@ class ErrorCodes(commands.Cog, name="errorcodes"):
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return errorcodes
cog = ErrorCodes(bot)
await bot.add_cog(cog)

View File

@@ -253,14 +253,11 @@ class ideviceView(discord.ui.View):
self.add_item(ideviceSelect(bot)) self.add_item(ideviceSelect(bot))
class idevice(commands.Cog, name="idevice"): def idevice_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="idevice", description="idevice troubleshooting and help" name="idevice", description="idevice troubleshooting and help"
) )
async def idevice(self, context: Context) -> None: async def idevice(self, context):
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:",
@@ -275,7 +272,4 @@ class idevice(commands.Cog, name="idevice"):
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return idevice
async def setup(bot) -> None:
await bot.add_cog(idevice(bot))

View File

@@ -4,16 +4,13 @@ from discord.ext.commands import Context
import os import os
class Mountddi(commands.Cog, name="mountddi"): def mountddi_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="mountddi", name="mountddi",
description="How to manually mount DDI" description="How to manually mount DDI"
) )
async def mountddi(self, ctx: Context) -> None: async def mountddi(self, context):
await ctx.defer() await context.defer()
embed = discord.Embed( embed = discord.Embed(
color=0xfa8c4a, color=0xfa8c4a,
@@ -46,15 +43,12 @@ class Mountddi(commands.Cog, name="mountddi"):
emoji="<:githubicon:1417717356846776340>" 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 ctx.send(embed=embed, view=view, file=file) await context.send(embed=embed, view=view, file=file)
else: else:
await ctx.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return mountddi
async def setup(bot) -> None:
await bot.add_cog(Mountddi(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Noapps(commands.Cog, name="noapps"): def noapps_command():
def __init__(self, bot) -> None:
self.bot = bot
@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: Context) -> None: async def noapps(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0xfa8c4a, color=0xfa8c4a,
description=( description=(
@@ -42,6 +39,4 @@ class Noapps(commands.Cog, name="noapps"):
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return noapps
async def setup(bot) -> None:
await bot.add_cog(Noapps(bot))

View File

@@ -0,0 +1,112 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
from .rickroll import rr_command
from .labubu import labubu_command
from .tryitandsee import tryitandsee_command
from .piracy import piracy_command
from .keanu import keanu_command
class Miscellaneous(commands.GroupCog, name="misc"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="miscellaneous", aliases=["misc"], invoke_without_command=True)
async def miscellaneous_group(self, context: Context):
embed = discord.Embed(
title="Miscellaneous Commands",
description="Use `.misc <subcommand>` or `/misc <subcommand>`.",
color=0x7289DA
)
embed.set_author(name="Miscellaneous", icon_url="https://yes.nighty.works/raw/YxMC0r.png")
embed.add_field(name="Available", value="rr, labubu, tryitandsee, piracy, keanu", inline=False)
await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command)
else:
await context.send(f"Unknown miscellaneous command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@miscellaneous_group.command(name="rr")
async def miscellaneous_group_rr(self, context: Context):
await self._invoke_hybrid(context, "rr")
@miscellaneous_group.command(name="labubu")
async def miscellaneous_group_labubu(self, context: Context):
await self._invoke_hybrid(context, "labubu")
@miscellaneous_group.command(name="tryitandsee")
async def miscellaneous_group_tryitandsee(self, context: Context):
await self._invoke_hybrid(context, "tryitandsee")
@miscellaneous_group.command(name="piracy")
async def miscellaneous_group_piracy(self, context: Context):
await self._invoke_hybrid(context, "piracy")
@miscellaneous_group.command(name="keanu")
async def miscellaneous_group_keanu(self, context: Context):
await self._invoke_hybrid(context, "keanu")
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="rr",
description="Rickroll"
)
async def rr(self, context):
return await rr_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="labubu",
description="Labubu ASCII art"
)
async def labubu(self, context):
return await labubu_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="tryitandsee",
description="Try it and see"
)
async def tryitandsee(self, context):
return await tryitandsee_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="piracy",
description="FBI Anti Piracy Warning"
)
async def piracy(self, context):
return await piracy_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="keanu",
description="Reeves"
)
async def keanu(self, context):
return await keanu_command()(self, context)
async def setup(bot) -> None:
cog = Miscellaneous(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'miscellaneous.rr'")
bot.logger.info("Loaded extension 'miscellaneous.labubu'")
bot.logger.info("Loaded extension 'miscellaneous.tryitandsee'")
bot.logger.info("Loaded extension 'miscellaneous.piracy'")
bot.logger.info("Loaded extension 'miscellaneous.keanu'")

View File

@@ -4,15 +4,12 @@ from discord.ext.commands import Context
import random import random
class Keanu(commands.Cog, name="keanu"): def keanu_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="keanu", name="keanu",
description="Reeves", description="Reeves",
) )
async def keanu(self, context: Context) -> None: async def keanu(self, context):
images = [ images = [
"https://yes.nighty.works/raw/z0HqUM.png", "https://yes.nighty.works/raw/z0HqUM.png",
"https://yes.nighty.works/raw/1Jc0j6.avif", "https://yes.nighty.works/raw/1Jc0j6.avif",
@@ -49,6 +46,4 @@ class Keanu(commands.Cog, name="keanu"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
return keanu
async def setup(bot) -> None:
await bot.add_cog(Keanu(bot))

View File

@@ -3,15 +3,12 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Labubu(commands.Cog, name="labubu"): def labubu_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="labubu", name="labubu",
description="Labubu ASCII art", description="Labubu ASCII art",
) )
async def labubu(self, context: Context) -> None: async def labubu(self, context):
labubu_art = """⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ labubu_art = """⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠗⠀⠀⣀⣄⠀⢿⣿⣿⣿⠟⠁⢠⡆⠉⠙⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠗⠀⠀⣀⣄⠀⢿⣿⣿⣿⠟⠁⢠⡆⠉⠙⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⣴⣿⡟⠀⠘⣿⣿⠋⠀⠀⠀⢠⣶⡀⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⣴⣿⡟⠀⠘⣿⣿⠋⠀⠀⠀⢠⣶⡀⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿
@@ -64,6 +61,4 @@ class Labubu(commands.Cog, name="labubu"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
return labubu
async def setup(bot) -> None:
await bot.add_cog(Labubu(bot))

View File

@@ -3,15 +3,12 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Piracy(commands.Cog, name="piracy"): def piracy_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="piracy", name="piracy",
description="FBI Anti Piracy Warning", description="FBI Anti Piracy Warning",
) )
async def piracy(self, context: Context) -> None: async def piracy(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0xE02B2B, color=0xE02B2B,
) )
@@ -28,6 +25,4 @@ class Piracy(commands.Cog, name="piracy"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
return piracy
async def setup(bot) -> None:
await bot.add_cog(Piracy(bot))

View File

@@ -3,15 +3,12 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Rr(commands.Cog, name="rr"): def rr_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="rr", name="rr",
description="Rickroll", description="Rickroll",
) )
async def rr(self, context: Context) -> None: async def rr(self, context):
gif_url = "https://yes.nighty.works/raw/JzjMcs.gif" gif_url = "https://yes.nighty.works/raw/JzjMcs.gif"
embed = discord.Embed( embed = discord.Embed(
@@ -29,6 +26,4 @@ class Rr(commands.Cog, name="rr"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
return rr
async def setup(bot) -> None:
await bot.add_cog(Rr(bot))

View File

@@ -3,15 +3,12 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class TryItAndSee(commands.Cog, name="tryitandsee"): def tryitandsee_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="tryitandsee", name="tryitandsee",
description="Try it and see", description="Try it and see",
) )
async def tryitandsee(self, context: Context) -> None: async def tryitandsee(self, context):
gif_url = "https://yes.nighty.works/raw/1BQP8c.gif" gif_url = "https://yes.nighty.works/raw/1BQP8c.gif"
embed = discord.Embed( embed = discord.Embed(
@@ -29,6 +26,4 @@ class TryItAndSee(commands.Cog, name="tryitandsee"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
return tryitandsee
async def setup(bot) -> None:
await bot.add_cog(TryItAndSee(bot))

139
cogs/moderation/__init__.py Normal file
View File

@@ -0,0 +1,139 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
from .ban import ban_command
from .kick import kick_command
from .purge import purge_command
from .warnings import warnings_command
from .archive import archive_command
from .hackban import hackban_command
from .nick import nick_command
class Moderation(commands.GroupCog, name="moderation"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="moderation", invoke_without_command=True)
async def moderation_group(self, context: Context):
embed = discord.Embed(
title="Moderation Commands",
description="Use `.moderation <subcommand>` or `/moderation <subcommand>`.",
color=0x7289DA
)
embed.add_field(name="Available", value="ban, kick, purge, warnings, archive, hackban, nick", inline=False)
await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command, **kwargs)
else:
await context.send(f"Unknown moderation command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@moderation_group.command(name="ban")
async def moderation_group_ban(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")
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)
@moderation_group.command(name="purge")
async def moderation_group_purge(self, context: Context, amount: int):
await self._invoke_hybrid(context, "purge", amount=amount)
@moderation_group.command(name="warnings")
async def moderation_group_warnings(self, context: Context):
await self._invoke_hybrid(context, "warnings")
@moderation_group.command(name="archive")
async def moderation_group_archive(self, context: Context, limit: int = 10):
await self._invoke_hybrid(context, "archive", limit=limit)
@moderation_group.command(name="hackban")
async def moderation_group_hackban(self, context: Context, user_id: int, *, reason: str = "Not specified"):
await self._invoke_hybrid(context, "hackban", user_id=user_id, reason=reason)
@moderation_group.command(name="nick")
async def moderation_group_nick(self, context: Context, user: discord.User, *, nickname: str = None):
await self._invoke_hybrid(context, "nick", user=user, nickname=nickname)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="ban",
description="Bans a user from the server."
)
async def ban(self, context, user: discord.User, *, 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.hybrid_command(
name="kick",
description="Kicks a user from the server."
)
async def kick(self, context, user: discord.User, *, reason: str = "Not specified"):
return await kick_command()(self, context, user=user, reason=reason)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="purge",
description="Delete a number of messages."
)
async def purge(self, context, amount: int):
return await purge_command()(self, context, amount=amount)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="warnings",
description="Manage warnings of a user on a server."
)
async def warnings(self, context):
return await warnings_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="archive",
description="Archives in a text file the last messages with a chosen limit of messages."
)
async def archive(self, context, limit: int = 10):
return await archive_command()(self, context, limit=limit)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="hackban",
description="Bans a user without the user having to be in the server."
)
async def hackban(self, context, user_id: int, *, reason: str = "Not specified"):
return await hackban_command()(self, context, user_id=user_id, reason=reason)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="nick",
description="Change the nickname of a user on a server."
)
async def nick(self, context, user: discord.User, *, nickname: str = None):
return await nick_command()(self, context, user=user, nickname=nickname)
async def setup(bot) -> None:
cog = Moderation(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'moderation.ban'")
bot.logger.info("Loaded extension 'moderation.kick'")
bot.logger.info("Loaded extension 'moderation.purge'")
bot.logger.info("Loaded extension 'moderation.warnings'")
bot.logger.info("Loaded extension 'moderation.archive'")
bot.logger.info("Loaded extension 'moderation.hackban'")
bot.logger.info("Loaded extension 'moderation.nick'")

View File

@@ -6,10 +6,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Archive(commands.Cog, name="archive"): def archive_command():
def __init__(self, bot) -> None:
self.bot = bot
@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.",
@@ -18,7 +15,7 @@ class Archive(commands.Cog, name="archive"):
@app_commands.describe( @app_commands.describe(
limit="The limit of messages that should be archived.", limit="The limit of messages that should be archived.",
) )
async def archive(self, context: Context, limit: int = 10) -> None: async def archive(self, context, limit: int = 10):
""" """
Archives in a text file the last messages with a chosen limit of messages. This command requires the MESSAGE_CONTENT intent to work properly. Archives in a text file the last messages with a chosen limit of messages. This command requires the MESSAGE_CONTENT intent to work properly.
@@ -55,6 +52,4 @@ class Archive(commands.Cog, name="archive"):
await context.send(file=f) await context.send(file=f)
os.remove(log_file) os.remove(log_file)
return archive
async def setup(bot) -> None:
await bot.add_cog(Archive(bot))

View File

@@ -4,10 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Ban(commands.Cog, name="ban"): def ban_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="ban", name="ban",
description="Bans a user from the server.", description="Bans a user from the server.",
@@ -27,8 +24,8 @@ class Ban(commands.Cog, name="ban"):
app_commands.Choice(name="Last 7 days", value="7d"), app_commands.Choice(name="Last 7 days", value="7d"),
]) ])
async def ban( async def ban(
self, context: 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"
) -> None: ):
try: try:
member = context.guild.get_member(user.id) member = context.guild.get_member(user.id)
if not member: if not member:
@@ -212,6 +209,4 @@ class Ban(commands.Cog, name="ban"):
} }
return time_formats.get(delete_option, "Unknown time period") return time_formats.get(delete_option, "Unknown time period")
return ban
async def setup(bot) -> None:
await bot.add_cog(Ban(bot))

View File

@@ -4,10 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class HackBan(commands.Cog, name="hackban"): def hackban_command():
def __init__(self, bot) -> None:
self.bot = bot
@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.",
@@ -19,8 +16,8 @@ class HackBan(commands.Cog, name="hackban"):
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: Context, user_id: str, *, reason: str = "Not specified" self, context, user_id: str, *, reason: str = "Not specified"
) -> None: ):
""" """
Bans a user without the user having to be in the server. Bans a user without the user having to be in the server.
@@ -48,6 +45,4 @@ class HackBan(commands.Cog, name="hackban"):
).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
async def setup(bot) -> None:
await bot.add_cog(HackBan(bot))

View File

@@ -4,10 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Kick(commands.Cog, name="kick"): def kick_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="kick", name="kick",
description="Kicks a user from the server.", description="Kicks a user from the server.",
@@ -17,8 +14,8 @@ class Kick(commands.Cog, name="kick"):
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: Context, user: discord.User, *, reason: str = "Not specified" self, context, user: discord.User, *, reason: str = "Not specified"
) -> None: ):
try: try:
member = context.guild.get_member(user.id) member = context.guild.get_member(user.id)
if not member: if not member:
@@ -123,6 +120,4 @@ class Kick(commands.Cog, name="kick"):
).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
async def setup(bot) -> None:
await bot.add_cog(Kick(bot))

View File

@@ -4,10 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Nick(commands.Cog, name="nick"): def nick_command():
def __init__(self, bot) -> None:
self.bot = bot
@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.",
@@ -17,8 +14,8 @@ class Nick(commands.Cog, name="nick"):
nickname="The new nickname that should be set.", nickname="The new nickname that should be set.",
) )
async def nick( async def nick(
self, context: Context, user: discord.User, *, nickname: str = None self, context, user: discord.User, *, nickname: str = None
) -> None: ):
""" """
Change the nickname of a user on a server. Change the nickname of a user on a server.
@@ -61,6 +58,4 @@ class Nick(commands.Cog, name="nick"):
).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
async def setup(bot) -> None:
await bot.add_cog(Nick(bot))

View File

@@ -4,10 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Purge(commands.Cog, name="purge"): def purge_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="purge", name="purge",
description="Delete a number of messages.", description="Delete a number of messages.",
@@ -15,13 +12,7 @@ class Purge(commands.Cog, name="purge"):
@commands.has_guild_permissions(manage_messages=True) @commands.has_guild_permissions(manage_messages=True)
@commands.bot_has_permissions(manage_messages=True) @commands.bot_has_permissions(manage_messages=True)
@app_commands.describe(amount="The amount of messages that should be deleted.") @app_commands.describe(amount="The amount of messages that should be deleted.")
async def purge(self, context: Context, amount: int) -> None: async def purge(self, context, amount: int):
"""
Delete a number of messages.
:param context: The hybrid command context.
:param amount: The number of messages that should be deleted.
"""
await context.send("Deleting messages...") await context.send("Deleting messages...")
purged_messages = await context.channel.purge(limit=amount + 1) purged_messages = await context.channel.purge(limit=amount + 1)
embed = discord.Embed( embed = discord.Embed(
@@ -32,6 +23,4 @@ class Purge(commands.Cog, name="purge"):
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 context.channel.send(embed=embed) await context.channel.send(embed=embed)
return purge
async def setup(bot) -> None:
await bot.add_cog(Purge(bot))

View File

@@ -4,11 +4,8 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
class Warnings(commands.Cog, name="warnings"): def warnings_command():
def __init__(self, bot) -> None: async def send_embed(context, embed: discord.Embed, *, ephemeral: bool = False) -> None:
self.bot = bot
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():
@@ -22,7 +19,7 @@ class Warnings(commands.Cog, name="warnings"):
name="warning", name="warning",
description="Manage warnings of a user on a server.", description="Manage warnings of a user on a server.",
) )
async def warning(self, context: Context) -> None: async def warning(self, context) -> None:
""" """
Manage warnings of a user on a server. Manage warnings of a user on a server.
@@ -170,5 +167,4 @@ class Warnings(commands.Cog, name="warnings"):
async def setup(bot) -> None: return warning
await bot.add_cog(Warnings(bot))

198
cogs/sidestore/__init__.py Normal file
View File

@@ -0,0 +1,198 @@
import discord
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import Context
from .sidestore import SidestoreView
from .refresh import refresh_command
from .code import code_command
from .crash import crash_command
from .pairing import pairing_command
from .server import server_command
from .afc import afc_command
from .udid import udid_command
from .half import half_command
from .sparse import sparse_command
class Sidestore(commands.GroupCog, name="sidestore"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="sidestore", invoke_without_command=True)
async def sidestore_group(self, context: Context):
embed = discord.Embed(
title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9
)
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot)
await context.send(embed=embed, view=view)
@sidestore_group.command(name="help")
async def sidestore_group_help(self, context: Context):
embed = discord.Embed(
title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9
)
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot)
await context.send(embed=embed, view=view)
async def _invoke_hybrid(self, context: Context, name: str):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command)
else:
await context.send(f"Unknown SideStore command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@sidestore_group.command(name="refresh")
async def sidestore_group_refresh(self, context: Context):
await self._invoke_hybrid(context, "refresh")
@sidestore_group.command(name="code")
async def sidestore_group_code(self, context: Context):
await self._invoke_hybrid(context, "code")
@sidestore_group.command(name="crash")
async def sidestore_group_crash(self, context: Context):
await self._invoke_hybrid(context, "crash")
@sidestore_group.command(name="pairing")
async def sidestore_group_pairing(self, context: Context):
await self._invoke_hybrid(context, "pairing")
@sidestore_group.command(name="server")
async def sidestore_group_server(self, context: Context):
await self._invoke_hybrid(context, "server")
@sidestore_group.command(name="afc")
async def sidestore_group_afc(self, context: Context):
await self._invoke_hybrid(context, "afc")
@sidestore_group.command(name="udid")
async def sidestore_group_udid(self, context: Context):
await self._invoke_hybrid(context, "udid")
@sidestore_group.command(name="half")
async def sidestore_group_half(self, context: Context):
await self._invoke_hybrid(context, "half")
@sidestore_group.command(name="sparse")
async def sidestore_group_sparse(self, context: Context):
await self._invoke_hybrid(context, "sparse")
@app_commands.command(
name="help",
description="SideStore troubleshooting help"
)
async def help(self, interaction: discord.Interaction):
embed = discord.Embed(
title="SideStore Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0x8e82f9
)
embed.set_author(name="SideStore", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true")
view = SidestoreView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="refresh",
description="Help with refreshing or installing apps"
)
async def refresh(self, context):
return await refresh_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="code",
description="No code received when signing in with Apple ID"
)
async def code(self, context):
return await code_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="crash",
description="Help with SideStore crashing issues"
)
async def crash(self, context):
return await crash_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="pairing",
description="Help with pairing file issues"
)
async def pairing(self, context):
return await pairing_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="server",
description="Help with anisette server issues"
)
async def server(self, context):
return await server_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="afc",
description="Help with AFC Connection Failure issues"
)
async def afc(self, context):
return await afc_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="udid",
description="SideStore could not determine device UDID"
)
async def udid(self, context):
return await udid_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="half",
description="Help with half-installed apps"
)
async def half(self, context):
return await half_command()(self, context)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="sparse",
description="Help with sparse bundle issues"
)
async def sparse(self, context):
return await sparse_command()(self, context)
async def setup(bot) -> None:
cog = Sidestore(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'sidestore.help'")
bot.logger.info("Loaded extension 'sidestore.refresh'")
bot.logger.info("Loaded extension 'sidestore.code'")
bot.logger.info("Loaded extension 'sidestore.crash'")
bot.logger.info("Loaded extension 'sidestore.pairing'")
bot.logger.info("Loaded extension 'sidestore.server'")
bot.logger.info("Loaded extension 'sidestore.afc'")
bot.logger.info("Loaded extension 'sidestore.udid'")
bot.logger.info("Loaded extension 'sidestore.half'")
bot.logger.info("Loaded extension 'sidestore.sparse'")

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Afc(commands.Cog, name="afc"): def afc_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="afc", description="Help with AFC Connection Failure issues" name="afc", description="Help with AFC Connection Failure issues"
) )
async def afc(self, context: Context) -> None: async def afc(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -45,5 +42,4 @@ class Afc(commands.Cog, name="afc"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return afc
await bot.add_cog(Afc(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Code(commands.Cog, name="code"): def code_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="code", description="No code received when signing in with Apple ID" name="code", description="No code received when signing in with Apple ID"
) )
async def code(self, context: Context) -> None: async def code(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -59,5 +56,4 @@ class Code(commands.Cog, name="code"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return code
await bot.add_cog(Code(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Crash(commands.Cog, name="crash"): def crash_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="crash", description="Help with SideStore crashing issues" name="crash", description="Help with SideStore crashing issues"
) )
async def crash(self, context: Context) -> None: async def crash(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -43,5 +40,4 @@ class Crash(commands.Cog, name="crash"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return crash
await bot.add_cog(Crash(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Half(commands.Cog, name="half"): def half_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="half", description="Help when apps get stuck installing" name="half", description="Help when apps get stuck installing"
) )
async def half(self, context: Context) -> None: async def half(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -52,5 +49,4 @@ class Half(commands.Cog, name="half"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return half
await bot.add_cog(Half(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Pairing(commands.Cog, name="pairing"): def pairing_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="pairing", description="Help with pairing file issues" name="pairing", description="Help with pairing file issues"
) )
async def pairing(self, context: Context) -> None: async def pairing(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -57,5 +54,4 @@ class Pairing(commands.Cog, name="pairing"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return pairing
await bot.add_cog(Pairing(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Refresh(commands.Cog, name="refresh"): def refresh_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="refresh", description="Help with refreshing or installing apps" name="refresh", description="Help with refreshing or installing apps"
) )
async def refresh(self, context: Context) -> None: async def refresh(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -47,5 +44,4 @@ class Refresh(commands.Cog, name="refresh"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return refresh
await bot.add_cog(Refresh(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Server(commands.Cog, name="server"): def server_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="server", description="Help with anisette server issues" name="server", description="Help with anisette server issues"
) )
async def server(self, context: Context) -> None: async def server(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -51,5 +48,4 @@ class Server(commands.Cog, name="server"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return server
await bot.add_cog(Server(bot))

View File

@@ -107,14 +107,11 @@ class SidestoreView(discord.ui.View):
self.add_item(SidestoreSelect(bot)) self.add_item(SidestoreSelect(bot))
class Sidestore(commands.Cog, name="sidestore"): def sidestore_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="sidestore", description="SideStore troubleshooting and help" name="help", description="SideStore troubleshooting and help"
) )
async def sidestore(self, context: Context) -> None: async def sidestore(self, context):
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:",
@@ -129,6 +126,4 @@ class Sidestore(commands.Cog, name="sidestore"):
else: else:
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return sidestore
async def setup(bot) -> None:
await bot.add_cog(Sidestore(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Sparse(commands.Cog, name="sparse"): def sparse_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="sparse", description="Information about SparseRestore exploit" name="sparse", description="Information about SparseRestore exploit"
) )
async def sparse(self, context: Context) -> None: async def sparse(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -46,5 +43,4 @@ class Sparse(commands.Cog, name="sparse"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return sparse
await bot.add_cog(Sparse(bot))

View File

@@ -5,14 +5,11 @@ from discord.ext.commands import Context
import time import time
class Udid(commands.Cog, name="udid"): def udid_command():
def __init__(self, bot) -> None:
self.bot = bot
@commands.hybrid_command( @commands.hybrid_command(
name="udid", description="SideStore could not determine device UDID" name="udid", description="SideStore could not determine device UDID"
) )
async def udid(self, context: Context) -> None: async def udid(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8e82f9, color=0x8e82f9,
description=( description=(
@@ -45,5 +42,4 @@ class Udid(commands.Cog, name="udid"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
async def setup(bot) -> None: return udid
await bot.add_cog(Udid(bot))

View File

@@ -0,0 +1,56 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
from .translate import translate_command
class Utilities(commands.GroupCog, name="utils"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="utilities", aliases=["utils"], invoke_without_command=True)
async def utilities_group(self, context: Context):
embed = discord.Embed(
title="Utilities Commands",
description="Use `.utils <subcommand>` or `/utils <subcommand>`.",
color=0x7289DA
)
embed.set_author(name="Utilities", icon_url="https://yes.nighty.works/raw/8VLDcg.webp")
embed.add_field(name="Available", value="translate", inline=False)
await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command, **kwargs)
else:
await context.send(f"Unknown utilities command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@utilities_group.command(name="translate")
async def utilities_group_translate(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)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="translate",
description="Translate text to another language"
)
async def translate(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)
async def setup(bot) -> None:
cog = Utilities(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'utilities.translate'")

View File

@@ -9,10 +9,8 @@ import json
import urllib.parse import urllib.parse
class Translate(commands.Cog, name="translate"): def translate_command():
def __init__(self, bot) -> None: languages = {
self.bot = bot
self.languages = {
"auto": "Auto-detect", "auto": "Auto-detect",
"en": "English", "en": "English",
"es": "Spanish", "es": "Spanish",
@@ -136,7 +134,7 @@ class Translate(commands.Cog, name="translate"):
"lv": "Latvian", "lv": "Latvian",
} }
async def send_embed(self, context: 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():
@@ -146,7 +144,7 @@ class Translate(commands.Cog, name="translate"):
else: else:
await context.send(embed=embed) await context.send(embed=embed)
async def _translate_with_google_web(self, 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"
@@ -196,11 +194,11 @@ class Translate(commands.Cog, name="translate"):
except Exception: except Exception:
return None return None
async def language_autocomplete(self, 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 = []
for code, name in self.languages.items(): for code, name in languages.items():
if current in code.lower() or current in name.lower(): if current in code.lower() or current in name.lower():
display_name = f"{code} - {name}" display_name = f"{code} - {name}"
if len(display_name) > 100: if len(display_name) > 100:
@@ -213,7 +211,7 @@ class Translate(commands.Cog, name="translate"):
if not choices: if not choices:
popular = ["en", "es", "fr", "de", "it", "pt", "ru", "ja", "ko", "zh-CN"] popular = ["en", "es", "fr", "de", "it", "pt", "ru", "ja", "ko", "zh-CN"]
for code in popular: for code in popular:
name = self.languages.get(code, code) name = languages.get(code, code)
choices.append(app_commands.Choice(name=f"{code} - {name}", value=code)) choices.append(app_commands.Choice(name=f"{code} - {name}", value=code))
return choices return choices
@@ -229,7 +227,7 @@ class Translate(commands.Cog, name="translate"):
) )
@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: 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
@@ -241,7 +239,7 @@ class Translate(commands.Cog, name="translate"):
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 self.send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
else: else:
embed = discord.Embed( embed = discord.Embed(
@@ -249,34 +247,34 @@ class Translate(commands.Cog, name="translate"):
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 self.send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
if to_lang not in self.languages: if to_lang not in languages:
embed = discord.Embed( embed = discord.Embed(
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 self.send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
if from_lang and from_lang not in self.languages: if from_lang and from_lang not in languages:
embed = discord.Embed( embed = discord.Embed(
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 self.send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
return return
result = await self._translate_with_google_web(text, from_lang or "auto", to_lang) result = await _translate_with_google_web(text, from_lang or "auto", to_lang)
if result and result.get("translatedText"): if result and result.get("translatedText"):
detected_lang = result.get("detectedSourceLanguage", from_lang or "auto") detected_lang = result.get("detectedSourceLanguage", from_lang or "auto")
from_lang_name = self.languages.get(detected_lang, detected_lang) from_lang_name = languages.get(detected_lang, detected_lang)
to_lang_name = self.languages.get(to_lang, to_lang) to_lang_name = languages.get(to_lang, to_lang)
embed = discord.Embed( embed = discord.Embed(
title="Translation", title="Translation",
@@ -286,18 +284,17 @@ class Translate(commands.Cog, name="translate"):
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 self.send_embed(context, embed) await send_embed(context, embed)
else: else:
embed = discord.Embed( embed = discord.Embed(
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 self.send_embed(context, embed, ephemeral=True) await send_embed(context, embed, ephemeral=True)
async def setup(bot): return translate
await bot.add_cog(Translate(bot))