2025-02-13 14:51:35 -05:00
|
|
|
import io
|
|
|
|
import random
|
|
|
|
import asyncio
|
|
|
|
import traceback
|
|
|
|
from typing import Optional
|
|
|
|
import discord
|
|
|
|
import requests
|
|
|
|
from discord.ext import bridge, commands
|
2025-02-15 08:36:45 -05:00
|
|
|
from disc_havoc import Havoc
|
2025-02-13 14:51:35 -05:00
|
|
|
import util
|
|
|
|
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
class Owner(commands.Cog):
|
|
|
|
"""Owner Cog for Havoc"""
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-15 08:36:45 -05:00
|
|
|
def __init__(self, bot: Havoc) -> None:
|
|
|
|
self.bot: Havoc = bot
|
|
|
|
self.former_roles_store: dict[int, list[discord.Role]] = {}
|
2025-02-13 14:51:35 -05:00
|
|
|
self._temperature: int = random.randrange(20, 30)
|
|
|
|
|
|
|
|
@bridge.bridge_command(guild_ids=[1145182936002482196])
|
2025-04-17 14:35:56 -04:00
|
|
|
async def temperature(self, ctx, temp: Optional[int | str] = None) -> None:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Set Temperature
|
|
|
|
"""
|
|
|
|
if not temp:
|
2025-04-17 14:35:56 -04:00
|
|
|
return await ctx.respond(
|
|
|
|
f"The current temperature is: {self._temperature} °C"
|
|
|
|
)
|
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
if not self.bot.is_owner(ctx.author):
|
|
|
|
return await ctx.respond("I am afraid I can't let you do that.")
|
|
|
|
try:
|
|
|
|
_temperature: int = int(temp)
|
|
|
|
except:
|
2025-04-17 14:35:56 -04:00
|
|
|
return await ctx.respond("Invalid input")
|
2025-02-13 14:51:35 -05:00
|
|
|
if _temperature < -15:
|
|
|
|
return await ctx.respond("Too cold! (-15°C minimum)")
|
|
|
|
elif _temperature > 35:
|
|
|
|
return await ctx.respond("Too hot! (35°C maximum)")
|
2025-02-15 08:36:45 -05:00
|
|
|
self._temperature = _temperature
|
2025-04-17 14:35:56 -04:00
|
|
|
return await ctx.respond(
|
|
|
|
f"As per your request, I have adjusted the temperature to {_temperature} °C."
|
|
|
|
)
|
|
|
|
|
2025-02-24 06:21:56 -05:00
|
|
|
@bridge.bridge_command()
|
|
|
|
@commands.is_owner()
|
2025-04-17 14:35:56 -04:00
|
|
|
async def editmsg(self, ctx, msgid: str, *, newcontent: str) -> None:
|
2025-02-24 06:21:56 -05:00
|
|
|
"""
|
|
|
|
Edit a message previously sent by the bot
|
|
|
|
"""
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-24 06:21:56 -05:00
|
|
|
try:
|
|
|
|
message: Optional[discord.Message] = self.bot.get_message(int(msgid))
|
|
|
|
if not message:
|
2025-04-17 14:35:56 -04:00
|
|
|
await ctx.respond(
|
|
|
|
f"**Failed:** Message {msgid} not found.", ephemeral=True
|
|
|
|
)
|
2025-02-24 06:21:56 -05:00
|
|
|
return None
|
|
|
|
await message.edit(content=newcontent)
|
|
|
|
await ctx.respond("**Done!**", ephemeral=True)
|
|
|
|
except Exception as e:
|
2025-04-17 14:35:56 -04:00
|
|
|
await ctx.respond(f"**Failed:** {str(e)}", ephemeral=True)
|
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@bridge.bridge_command()
|
|
|
|
@commands.is_owner()
|
|
|
|
async def reload(self, ctx) -> None:
|
|
|
|
"""
|
|
|
|
Reload Cogs
|
|
|
|
"""
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
self.bot.load_exts(False)
|
|
|
|
await ctx.respond("Reloaded!", ephemeral=True)
|
|
|
|
|
|
|
|
@bridge.bridge_command()
|
|
|
|
@commands.is_owner()
|
2025-04-17 14:35:56 -04:00
|
|
|
async def say(self, ctx, *, parameters: str) -> None:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Make me say something in a channel
|
|
|
|
"""
|
2025-02-15 08:36:45 -05:00
|
|
|
_parameters: list[str] = parameters.split(" ")
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-15 08:36:45 -05:00
|
|
|
if not len(_parameters) > 1:
|
2025-04-17 14:35:56 -04:00
|
|
|
return await ctx.respond(
|
|
|
|
"**Error**: Incorrect command usage; required: <chan> <msg>",
|
|
|
|
ephemeral=True,
|
|
|
|
)
|
|
|
|
|
2025-02-15 08:36:45 -05:00
|
|
|
channel: str = _parameters[0]
|
|
|
|
channel_mentions: list[int] = discord.utils.raw_channel_mentions(channel)
|
2025-02-13 14:51:35 -05:00
|
|
|
if channel_mentions:
|
2025-02-15 08:36:45 -05:00
|
|
|
channel = str(channel_mentions[0])
|
2025-03-12 07:40:56 -04:00
|
|
|
msg: str = " ".join(_parameters[1:])
|
2025-04-17 14:35:56 -04:00
|
|
|
await util.discord_helpers.send_message(self.bot, channel=channel, message=msg)
|
2025-02-13 14:51:35 -05:00
|
|
|
return await ctx.respond("**Done.**", ephemeral=True)
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@bridge.bridge_command()
|
|
|
|
@commands.is_owner()
|
2025-04-17 14:35:56 -04:00
|
|
|
async def chgstatus(self, ctx, *, status: Optional[str] = None) -> None:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Change bots status
|
|
|
|
"""
|
|
|
|
if not status:
|
2025-04-17 14:35:56 -04:00
|
|
|
return await ctx.respond(
|
|
|
|
"ERR: No status provided to change to!", ephemeral=True
|
|
|
|
)
|
|
|
|
|
|
|
|
await self.bot.change_presence(
|
|
|
|
status=discord.Status.online,
|
|
|
|
activity=discord.CustomActivity(name=status.strip()),
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
await ctx.respond("Done!", ephemeral=True)
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@commands.message_command(name="Remove Messages Starting Here")
|
|
|
|
@commands.is_owner()
|
|
|
|
async def purge(self, ctx, message: discord.Message) -> None:
|
|
|
|
"""
|
|
|
|
Purge Messages
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
ctx (Any): Discord context
|
|
|
|
message (discord.Message): Discord message
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
"""
|
|
|
|
try:
|
2025-04-17 14:35:56 -04:00
|
|
|
await ctx.channel.purge(
|
|
|
|
after=message,
|
|
|
|
bulk=True,
|
|
|
|
limit=900000,
|
|
|
|
reason=f"Purge initiated by {ctx.author.display_name}",
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
await message.delete(reason=f"Purge initiated by {ctx.author.display_name}")
|
|
|
|
await ctx.respond("**Done!**")
|
|
|
|
# Wait 3 seconds, then delete interaction
|
|
|
|
await asyncio.sleep(3)
|
|
|
|
interaction = await ctx.interaction.original_response()
|
|
|
|
await interaction.delete()
|
|
|
|
except Exception as e:
|
|
|
|
traceback.print_exc()
|
|
|
|
return await ctx.respond(f"**ERR: {str(e)}**")
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@commands.message_command(name="Move to Memes")
|
|
|
|
@commands.is_owner()
|
|
|
|
async def movememe(self, ctx, message: discord.Message) -> None:
|
|
|
|
"""
|
|
|
|
Move to Memes
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
ctx (Any): Discord context
|
|
|
|
message (discord.Message): Discord message
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
"""
|
|
|
|
try:
|
2025-02-15 08:36:45 -05:00
|
|
|
if not isinstance(message.channel, discord.TextChannel):
|
|
|
|
return
|
2025-04-17 14:35:56 -04:00
|
|
|
memes_channel: discord.TextChannel = ctx.guild.get_channel(
|
|
|
|
1147229098544988261
|
|
|
|
)
|
|
|
|
message_content: str = message.content
|
2025-02-13 14:51:35 -05:00
|
|
|
message_author: str = message.author.display_name
|
|
|
|
message_channel: str = message.channel.name
|
|
|
|
_file: Optional[discord.File] = None
|
|
|
|
if message.attachments:
|
|
|
|
for item in message.attachments:
|
|
|
|
if item.url and len(item.url) >= 20:
|
2025-04-17 14:35:56 -04:00
|
|
|
image: io.BytesIO = io.BytesIO(
|
|
|
|
requests.get(item.url, stream=True, timeout=20).raw.read()
|
|
|
|
)
|
|
|
|
ext: str = item.url.split(".")[-1].split("?")[0].split("&")[0]
|
|
|
|
_file = discord.File(image, filename=f"img.{ext}")
|
2025-02-15 08:36:45 -05:00
|
|
|
if not _file:
|
2025-04-17 14:35:56 -04:00
|
|
|
return # No file to move
|
|
|
|
await memes_channel.send(
|
|
|
|
f"*Performing bureaucratic duties (this didn't belong in #{message_channel})...*\n**{message_author}:** {message_content}",
|
|
|
|
file=_file,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
await message.delete()
|
|
|
|
await ctx.respond("OK!", ephemeral=True)
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
return await ctx.respond("Failed! :(", ephemeral=True)
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@commands.message_command(name="Move to Drugs")
|
|
|
|
@commands.is_owner()
|
|
|
|
async def movedrugs(self, ctx, message: discord.Message) -> None:
|
|
|
|
"""
|
|
|
|
Move to Drugs
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
ctx (Any): Discord context
|
|
|
|
message (discord.Message): Discord message
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
"""
|
|
|
|
try:
|
2025-02-15 08:36:45 -05:00
|
|
|
if not isinstance(message.channel, discord.TextChannel):
|
|
|
|
return
|
2025-04-17 14:35:56 -04:00
|
|
|
drugs_channel: discord.TextChannel = ctx.guild.get_channel(
|
|
|
|
1172247451047034910
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
message_content: str = message.content
|
|
|
|
message_author: str = message.author.display_name
|
|
|
|
message_channel: str = message.channel.name
|
|
|
|
_file: Optional[discord.File] = None
|
|
|
|
if message.attachments:
|
|
|
|
for item in message.attachments:
|
|
|
|
if item.url and len(item.url) >= 20:
|
2025-04-17 14:35:56 -04:00
|
|
|
image: io.BytesIO = io.BytesIO(
|
|
|
|
requests.get(item.url, stream=True, timeout=20).raw.read()
|
|
|
|
)
|
|
|
|
ext: str = item.url.split(".")[-1].split("?")[0].split("&")[0]
|
|
|
|
_file = discord.File(image, filename=f"img.{ext}")
|
2025-02-15 08:36:45 -05:00
|
|
|
if not _file:
|
2025-04-17 14:35:56 -04:00
|
|
|
return # No file to move
|
|
|
|
await drugs_channel.send(
|
|
|
|
f"*Performing bureaucratic duties (this didn't belong in #{message_channel})...\
|
|
|
|
*\n**{message_author}:** {message_content}",
|
|
|
|
file=_file,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
await message.delete()
|
|
|
|
await ctx.respond("OK!", ephemeral=True)
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
return await ctx.respond("Failed! :(", ephemeral=True)
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@commands.message_command(name="Move to fun-house")
|
|
|
|
@commands.is_owner()
|
|
|
|
async def movefunhouse(self, ctx, message: discord.Message) -> None:
|
|
|
|
"""
|
|
|
|
Move to fun-house
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
ctx (Any): Discord context
|
|
|
|
message (discord.Message): Discord message
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
"""
|
|
|
|
try:
|
2025-02-15 08:36:45 -05:00
|
|
|
if not isinstance(message.channel, discord.TextChannel):
|
|
|
|
return
|
2025-04-17 14:35:56 -04:00
|
|
|
funhouse_channel: discord.TextChannel = ctx.guild.get_channel(
|
|
|
|
1213160512364478607
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
message_content: str = message.content
|
|
|
|
message_author: str = message.author.display_name
|
|
|
|
message_channel: str = message.channel.name
|
|
|
|
_file: Optional[discord.File] = None
|
|
|
|
if message.attachments:
|
|
|
|
for item in message.attachments:
|
|
|
|
if item.url and len(item.url) >= 20:
|
2025-04-17 14:35:56 -04:00
|
|
|
image: io.BytesIO = io.BytesIO(
|
|
|
|
requests.get(item.url, stream=True, timeout=20).raw.read()
|
|
|
|
)
|
|
|
|
ext: str = item.url.split(".")[-1].split("?")[0].split("&")[0]
|
|
|
|
_file = discord.File(image, filename=f"img.{ext}")
|
|
|
|
await funhouse_channel.send(
|
|
|
|
f"*Performing bureaucratic duties (this didn't belong in #{message_channel})\
|
|
|
|
...*\n**{message_author}:** {message_content}"
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
await message.delete()
|
|
|
|
await ctx.respond("OK!", ephemeral=True)
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
return await ctx.respond("Failed! :(", ephemeral=True)
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
@commands.user_command(name="Einsperren!", guild_ids=[145182936002482196])
|
|
|
|
@commands.is_owner()
|
|
|
|
async def einsperren(self, ctx, member: discord.Member) -> None:
|
|
|
|
"""
|
|
|
|
Einsperren!
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
ctx (Any): Discord context
|
|
|
|
member (discord.Member): Discord member
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
if not ctx.guild.id == 1145182936002482196:
|
2025-04-17 14:35:56 -04:00
|
|
|
return # Not home server!
|
2025-02-15 08:36:45 -05:00
|
|
|
if not member.roles:
|
2025-04-17 14:35:56 -04:00
|
|
|
return # No roles
|
2025-02-13 14:51:35 -05:00
|
|
|
audit_reason: str = f"Einsperren von {ctx.user.display_name}"
|
2025-02-15 08:36:45 -05:00
|
|
|
member = ctx.guild.get_member(member.id)
|
2025-02-13 14:51:35 -05:00
|
|
|
member_display: str = member.display_name
|
2025-04-17 14:35:56 -04:00
|
|
|
einsperren_role: discord.Role = (
|
|
|
|
ctx.guild.get_role(1235415059300093973)
|
|
|
|
if ctx.guild.id != 1145182936002482196
|
2025-02-13 14:51:35 -05:00
|
|
|
else ctx.guild.get_role(1235406301614309386)
|
2025-04-17 14:35:56 -04:00
|
|
|
)
|
|
|
|
member_roles: list = [
|
|
|
|
role for role in member.roles if not role.name == "@everyone"
|
|
|
|
]
|
|
|
|
member_role_names: list[str] = [
|
|
|
|
str(role.name).lower() for role in member_roles
|
|
|
|
]
|
2025-02-13 14:51:35 -05:00
|
|
|
opers_chan: discord.TextChannel = ctx.guild.get_channel(1181416083287187546)
|
|
|
|
if not "einsperren" in member_role_names:
|
|
|
|
try:
|
|
|
|
if member.id in self.former_roles_store:
|
|
|
|
self.former_roles_store.pop(member.id)
|
|
|
|
self.former_roles_store[member.id] = member.roles
|
|
|
|
except:
|
2025-04-17 14:35:56 -04:00
|
|
|
pass # Safe to ignore
|
2025-02-13 14:51:35 -05:00
|
|
|
try:
|
|
|
|
await member.edit(roles=[einsperren_role], reason=audit_reason)
|
2025-04-17 14:35:56 -04:00
|
|
|
await ctx.respond(
|
|
|
|
f"Gesendet {member_display} an einsperren.", ephemeral=True
|
|
|
|
)
|
|
|
|
await opers_chan.send(
|
|
|
|
f"@everyone: {ctx.user.display_name} gesendet {member_display} an einsperren."
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
return await ctx.respond("GOTTVERDAMMT!!", ephemeral=True)
|
|
|
|
self.former_roles_store[member.id] = member.roles
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
if not member.id in self.former_roles_store:
|
|
|
|
await member.edit(roles=[]) # No roles
|
|
|
|
else:
|
2025-02-15 08:36:45 -05:00
|
|
|
former_roles: list = self.former_roles_store.get(member.id, [0])
|
2025-02-13 14:51:35 -05:00
|
|
|
await member.edit(roles=former_roles, reason=f"De-{audit_reason}")
|
2025-04-17 14:35:56 -04:00
|
|
|
|
|
|
|
await ctx.respond(
|
|
|
|
f"{member_display} wurde von der Einsperre befreit.", ephemeral=True
|
|
|
|
)
|
|
|
|
await opers_chan.send(
|
|
|
|
f"{member_display} wurde von {ctx.user.display_name} aus der Einsperre befreit."
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
except Exception as e:
|
|
|
|
traceback.print_exc()
|
|
|
|
return await ctx.respond(f"ERR: {str(e)}", ephemeral=True)
|
|
|
|
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
def setup(bot) -> None:
|
|
|
|
"""Run on Cog Load"""
|
2025-04-17 14:35:56 -04:00
|
|
|
bot.add_cog(Owner(bot))
|