Initial commit v2 (token free)

This commit is contained in:
Xargana 2025-05-07 17:44:50 +03:00
parent 93235081ea
commit 0cd926b9a7
19 changed files with 1458 additions and 0 deletions

1
bot/__init__.py Normal file
View file

@ -0,0 +1 @@
# Empty init to make directory a package

1
bot/commands/__init__.py Normal file
View file

@ -0,0 +1 @@
# Empty init to make directory a package

View file

@ -0,0 +1,65 @@
import os
from config import COMMANDS_DIR
from utils.storage import save_tracked_channels
class AdminCommands:
def __init__(self, bot):
self.bot = bot
async def cmd_addcmd(self, message):
"""Add a custom command"""
try:
parts = message.content.split(" ", 2)
if len(parts) < 3:
await message.reply("Usage: .addcmd <name> <code>", silent=True)
return
cmd_name, code = parts[1], parts[2]
cmd_path = os.path.join(COMMANDS_DIR, f"{cmd_name}.py")
with open(cmd_path, "w") as f:
f.write("async def run(msg):\n")
for line in code.split("\n"):
f.write(f" {line}\n")
self.bot.reload_commands()
await message.reply(f"Command {cmd_name} saved.", silent=True)
except Exception as e:
await message.reply(f"Error: {e}", silent=True)
async def cmd_delcmd(self, message):
"""Delete a custom command"""
cmd_name = message.content.split(" ", 1)[1]
cmd_path = os.path.join(COMMANDS_DIR, f"{cmd_name}.py")
if os.path.exists(cmd_path):
os.remove(cmd_path)
self.bot.reload_commands()
await message.reply(f"Command {cmd_name} deleted.", silent=True)
else:
await message.reply(f"Command {cmd_name} not found.", silent=True)
async def cmd_listcmds(self, message):
"""List all custom commands"""
cmds = list(self.bot.loaded_commands.keys())
await message.reply("Saved commands:\n" + ", ".join(cmds) if cmds else "No saved commands.", silent=True)
async def cmd_trackmessages(self, message):
"""Start tracking messages in the current channel"""
channel_id = message.channel.id
if channel_id not in self.bot.tracked_channels:
self.bot.tracked_channels.append(channel_id)
save_tracked_channels(self.bot.tracked_channels)
await message.reply(f"Tracking messages in this channel {message.channel.name}.", silent=True)
else:
await message.reply("This channel is already being tracked.", silent=True)
async def cmd_untrackmessages(self, message):
"""Stop tracking messages in the current channel"""
channel_id = message.channel.id
if channel_id in self.bot.tracked_channels:
self.bot.tracked_channels.remove(channel_id)
save_tracked_channels(self.bot.tracked_channels)
await message.reply(f"Stopped tracking messages in {message.channel.name}.", silent=True)
else:
await message.reply("This channel is not being tracked.", silent=True)

View file

@ -0,0 +1,38 @@
class AfkCommands:
def __init__(self, bot):
self.bot = bot
async def handle_afk_dm(self, message):
"""Handle DMs when in AFK mode"""
if self.bot.AFK_STATUS and message.author.id not in self.bot.AFK_NOTIFIED_USERS:
await message.reply(
"Heya, I'm not at my computer right now, if you're requesting something please follow <https://nohello.club>. I'll let you know when I'm back :) \n\n-# This action was automated."
)
self.bot.AFK_NOTIFIED_USERS.append(message.author.id)
async def cmd_afk(self, message):
"""Enable AFK mode"""
if not self.bot.AFK_STATUS:
self.bot.AFK_STATUS = True
await message.reply("k")
else:
await message.reply("You are already in AFK mode.", silent=True)
async def cmd_unafk(self, message):
"""Disable AFK mode"""
if self.bot.AFK_STATUS:
self.bot.AFK_STATUS = False
for i in self.bot.AFK_NOTIFIED_USERS:
try:
user = await self.bot.fetch_user(i)
if user:
dm_channel = await user.create_dm()
await dm_channel.send("Hey, I'm back, human me will take over now!")
except Exception as e:
raise RuntimeWarning from e
self.bot.AFK_NOTIFIED_USERS.clear()
await message.reply("should work")
else:
await message.reply("You are not in AFK mode.", silent=True)

View file

@ -0,0 +1,65 @@
import random
import asyncio
class FunCommands:
def __init__(self, bot):
self.bot = bot
async def cmd_horse(self, message):
"""Toggle horse reactions in a channel"""
if message.channel.id in self.bot.horsin:
self.bot.horsin.remove(message.channel.id)
await message.reply("no longer horsin around D:")
else:
self.bot.horsin.append(message.channel.id)
await message.reply(":D")
async def cmd_rps(self, message):
"""Play rock, paper, scissors"""
parts = message.content.split(" ", 1)
if len(parts) != 2:
await message.reply("Usage: `.rps <item>`", silent=True)
return
item = parts[1]
# Easter eggs
if item.lower() == "dick":
await message.reply("Scissors beats dick any day :3", silent=True)
return
if item == "<@696800726084747314>":
await message.reply("Head so thick that i would try rock but the rock would break")
return
# The main game
choice = random.choice([1, 2, 3]) # 1=rock, 2=paper, 3=scissors
rps_map = {1: 'r', 2: 'p', 3: 's'}
rps_map_reverse = {'r': 1, 'p': 2, 's': 3} # Fixed the reversed mapping
shortmaps = {'r': 'rock', 'p': 'paper', 's': 'scissors'}
beat_map = {1: 3, 2: 1, 3: 2} # What beats what: rock>scissors, paper>rock, scissors>paper
# Determine user choice
iid = 0
for k, v in rps_map_reverse.items():
if item.lower().startswith(k):
iid = v
break
if iid == 0:
await message.reply("Invalid choice!", silent=True)
return
if choice == iid:
await message.reply(f"Huh we chose the same thing. Try again!", silent=True)
elif beat_map[iid] == choice:
await message.reply(f"Welp, ggs, I won. I chose `{shortmaps[rps_map[choice]]}`", silent=True)
else:
await message.reply(f"Oop, you lost. Try again later! I chose `{shortmaps[rps_map[choice]]}`", silent=True)
async def cmd_repeat(self, message):
"""Repeat a message every 29 minutes"""
await message.reply("oop ok")
while True:
await message.channel.send("you asked dad")
await asyncio.sleep(29 * 60) # 29 minutes

View file

@ -0,0 +1,430 @@
import asyncio
import time
import inspect
import traceback
from datetime import datetime
class TestCommands:
def __init__(self, bot):
self.bot = bot
self.tests = {
"afk": self.test_afk,
"remindme": self.test_remindme,
"commands": self.test_commands,
"storage": self.test_storage,
"health": self.test_health,
"all": self.test_all,
}
async def cmd_test(self, message):
"""Run self-tests on the bot"""
parts = message.content.split(" ", 1)
test_name = parts[1] if len(parts) > 1 else "all"
if test_name not in self.tests:
await message.channel.send(
f"Unknown test '{test_name}'. Available tests: {', '.join(self.tests.keys())}"
)
return
# Create a status message without silent flag for better visibility
status_msg = await message.channel.send(f"🔄 Running test: {test_name}...")
start_time = time.time()
try:
if test_name == "all":
# For "all" tests, update status more frequently
await status_msg.edit(content="🔄 Initializing test suite...")
results = await self.test_all(status_msg)
else:
test_func = self.tests[test_name]
results = await test_func(status_msg)
elapsed = time.time() - start_time
# Format results into a nice report
report = self._format_test_report(results, elapsed)
# Make sure report isn't too long for Discord
if len(report) > 2000:
report = report[:1997] + "..."
# Update status with results
await status_msg.edit(content=report)
except Exception as e:
error_msg = f"❌ Test failed with error:\n\n{traceback.format_exc()[:1500]}\n"
print(f"Test error: {str(e)}")
await status_msg.edit(content=error_msg)
def _format_test_report(self, results, elapsed):
"""Format test results into a readable report"""
if isinstance(results, dict):
# We have multiple test suites
total_passed = sum(r['passed'] for r in results.values())
total_failed = sum(r['failed'] for r in results.values())
total_tests = total_passed + total_failed
report = f"# Self-Test Report ({elapsed:.2f}s)\n\n"
report += f"✅ **{total_passed}/{total_tests}** tests passed\n"
if total_failed > 0:
report += f"❌ **{total_failed}** tests failed\n\n"
else:
report += "\n"
# Add individual test suite results
for suite_name, suite_result in results.items():
passed = suite_result['passed']
failed = suite_result['failed']
total = passed + failed
status = "" if failed == 0 else "⚠️"
report += f"{status} **{suite_name}**: {passed}/{total} passed\n"
# Add failure details if any
if failed > 0 and 'failures' in suite_result:
report += "\n"
for failure in suite_result['failures']:
report += f"{failure}\n"
report += "\n"
else:
# Single test suite
passed = results['passed']
failed = results['failed']
total = passed + failed
report = f"# Test Results ({elapsed:.2f}s)\n\n"
report += f"✅ **{passed}/{total}** tests passed\n"
if failed > 0:
report += f"❌ **{failed}** tests failed\n\n"
report += "\n"
for failure in results.get('failures', []):
report += f"{failure}\n"
report += "\n"
return report
async def test_all(self, status_msg):
"""Run all available tests"""
results = {}
test_funcs = [v for k, v in self.tests.items() if k != "all"]
for i, test_func in enumerate(test_funcs):
test_name = test_func.__name__.replace('test_', '')
try:
# Update status before each test
await status_msg.edit(content=f"🔄 Running tests ({i+1}/{len(test_funcs)}): {test_name}...")
results[test_name] = await test_func(status_msg)
# Quick status after each test
passed = results[test_name]['passed']
failed = results[test_name]['failed']
await status_msg.edit(content=f"🔄 Test {test_name}: ✅{passed}{failed} | Continuing tests...")
except Exception as e:
results[test_name] = {'passed': 0, 'failed': 1, 'failures': [f"Exception: {str(e)}"]}
await status_msg.edit(content=f"⚠️ Error in test {test_name}, continuing with next test...")
return results
async def test_afk(self, status_msg):
"""Test AFK functionality"""
results = {'passed': 0, 'failed': 0, 'failures': []}
# Save original state
original_afk = self.bot.AFK_STATUS
original_notified = self.bot.AFK_NOTIFIED_USERS.copy()
try:
# Test 1: Enable AFK
self.bot.AFK_STATUS = False
await self.bot.afk_commands.cmd_afk(status_msg)
if self.bot.AFK_STATUS:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Failed to enable AFK mode")
# Test 2: Disable AFK
await self.bot.afk_commands.cmd_unafk(status_msg)
if not self.bot.AFK_STATUS:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Failed to disable AFK mode")
# Test 3: AFK notification list clears
if len(self.bot.AFK_NOTIFIED_USERS) == 0:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("AFK notified users list not cleared")
finally:
# Restore original state
self.bot.AFK_STATUS = original_afk
self.bot.AFK_NOTIFIED_USERS = original_notified
return results
async def test_remindme(self, status_msg):
"""Test reminder functionality with a very short reminder"""
results = {'passed': 0, 'failed': 0, 'failures': []}
# Create a test reminder message
test_content = ".remindme 1s Test reminder"
mock_message = MockMessage(
author=self.bot.user,
content=test_content,
channel=status_msg.channel
)
# Set up a flag to verify the reminder was triggered
reminder_triggered = False
original_reply = mock_message.reply
async def mock_reply(content, **kwargs):
nonlocal reminder_triggered
if "Reminder:" in content:
reminder_triggered = True
return await original_reply(content, **kwargs)
mock_message.reply = mock_reply
try:
# Test reminder setup
await self.bot.utility_commands.cmd_remindme(mock_message)
# Wait for the reminder to trigger (slightly more than 1s)
await asyncio.sleep(1.5)
if reminder_triggered:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Reminder did not trigger")
except Exception as e:
results['failed'] += 1
results['failures'].append(f"Reminder test error: {str(e)}")
return results
async def test_commands(self, status_msg):
"""Test custom command functionality"""
results = {'passed': 0, 'failed': 0, 'failures': []}
# Test command name
test_cmd_name = "__test_cmd__"
test_cmd_path = f"commands/{test_cmd_name}.py"
try:
# Test 1: Add a command
add_cmd_msg = MockMessage(
author=self.bot.user,
content=f".addcmd {test_cmd_name} return await msg.reply('test success', silent=True)",
channel=status_msg.channel
)
await self.bot.admin_commands.cmd_addcmd(add_cmd_msg)
if test_cmd_name in self.bot.loaded_commands:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Failed to add test command")
# Test 2: Execute the command
if test_cmd_name in self.bot.loaded_commands:
try:
test_msg = MockMessage(
author=self.bot.user,
content="test content",
channel=status_msg.channel
)
reply_received = False
original_reply = test_msg.reply
async def test_reply(content, **kwargs):
nonlocal reply_received
if content == "test success":
reply_received = True
return await original_reply(content, **kwargs)
test_msg.reply = test_reply
await self.bot.loaded_commands[test_cmd_name](test_msg)
if reply_received:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Command execution failed")
except Exception as e:
results['failed'] += 1
results['failures'].append(f"Command execution error: {str(e)}")
# Test 3: Delete the command
del_cmd_msg = MockMessage(
author=self.bot.user,
content=f".delcmd {test_cmd_name}",
channel=status_msg.channel
)
await self.bot.admin_commands.cmd_delcmd(del_cmd_msg)
if test_cmd_name not in self.bot.loaded_commands:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Failed to delete test command")
except Exception as e:
results['failed'] += 1
results['failures'].append(f"Command test error: {str(e)}")
# Clean up any leftovers
import os
if os.path.exists(test_cmd_path):
try:
os.remove(test_cmd_path)
self.bot.reload_commands()
except:
pass
return results
async def test_storage(self, status_msg):
"""Test channel tracking functionality"""
results = {'passed': 0, 'failed': 0, 'failures': []}
# Save original state
original_tracked = self.bot.tracked_channels.copy()
try:
# Test channel ID that likely doesn't exist
test_channel_id = 1349095349905788968
# Make sure it's not in the tracked channels
if test_channel_id in self.bot.tracked_channels:
self.bot.tracked_channels.remove(test_channel_id)
# Test 1: Add a tracked channel
self.bot.tracked_channels.append(test_channel_id)
from utils.storage import save_tracked_channels
save_tracked_channels(self.bot.tracked_channels)
# Test 2: Load tracked channels
from utils.storage import load_tracked_channels
loaded_channels = load_tracked_channels()
if test_channel_id in loaded_channels:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Failed to save/load tracked channel")
# Test 3: Remove tracked channel
if test_channel_id in self.bot.tracked_channels:
self.bot.tracked_channels.remove(test_channel_id)
save_tracked_channels(self.bot.tracked_channels)
loaded_channels = load_tracked_channels()
if test_channel_id not in loaded_channels:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Failed to remove tracked channel")
finally:
# Restore original state
self.bot.tracked_channels = original_tracked
from utils.storage import save_tracked_channels
save_tracked_channels(self.bot.tracked_channels)
return results
async def test_health(self, status_msg):
"""Test basic bot health and connectivity"""
results = {'passed': 0, 'failed': 0, 'failures': []}
# Test 1: Check if the bot is logged in
if self.bot.user is not None:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append("Bot is not logged in")
# Test 2: Check discord API connection by getting client latency
try:
latency = self.bot.latency
if isinstance(latency, float):
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append(f"Invalid latency value: {latency}")
except Exception as e:
results['failed'] += 1
results['failures'].append(f"Failed to get latency: {str(e)}")
# Test 3: Test message sending/editing (core functionality)
try:
test_msg = await status_msg.channel.send(
"Test message - will be deleted", silent=False
)
await test_msg.edit(content="Test message edited - will be deleted")
await test_msg.delete()
results['passed'] += 1
except Exception as e:
results['failed'] += 1
results['failures'].append(f"Message operations failed: {str(e)}")
return results
def _assert(self, results, condition, message):
"""Helper method for assertions in tests"""
if condition:
results['passed'] += 1
else:
results['failed'] += 1
results['failures'].append(message)
return condition
class MockMessage:
"""A mock message class for testing"""
def __init__(self, author, content, channel):
self.author = author
self.content = content
self.channel = channel
self.id = int(time.time() * 1000)
self.created_at = datetime.now()
async def reply(self, content, **kwargs):
"""Mock reply method"""
return await self.channel.send(f"Reply to {self.id}: {content}", **kwargs)
async def edit(self, **kwargs):
"""Mock edit method"""
self.content = kwargs.get('content', self.content)
return self
async def cmd_test_debug(self, message):
"""Run a simple debug test to verify command functionality"""
try:
# Send a simple message that should always work
debug_msg = await message.channel.send("🔍 Debug test initiated...")
# Wait a moment
await asyncio.sleep(1)
# Edit the message
await debug_msg.edit(content="✅ Debug test successful - message editing works!")
except Exception as e:
# If this fails, there's a fundamental issue
await message.channel.send(f"❌ Debug test failed: {str(e)}")

View file

@ -0,0 +1,142 @@
import asyncio
import traceback
import datetime
import os
import ast
import gzip
import json
from utils.time_parser import parse_time
from config import DOWNLOADS_DIR
class UtilityCommands:
def __init__(self, bot):
self.bot = bot
async def cmd_remindme(self, message):
"""Set a reminder"""
parts = message.content.split(" ", 2)
if len(parts) < 3:
await message.reply("Usage: `.remindme <time> <message>`", silent=True)
else:
duration = parse_time(parts[1])
if duration is None:
await message.reply("Invalid time format. Example: `4m2s`, `1h30m`.", silent=True)
else:
reminder_text = parts[2]
await message.reply(f"Reminder set for {parts[1]}.", silent=True)
async def reminder_task():
await asyncio.sleep(duration)
await message.reply(f"{message.author.mention} Reminder: {reminder_text.replace('@', 'at')}")
asyncio.create_task(reminder_task())
async def cmd_fmt(self, message):
"""Format a string using f-string"""
try:
formatted = eval(f"f'{message.content[5:]}'", globals(), locals())
print(formatted)
await asyncio.wait_for(message.edit(formatted), timeout=5)
except Exception as e:
flashdel = await message.channel.send(f"Error: {e}", silent=True)
await message.delete()
await flashdel.delete()
raise RuntimeWarning from e
async def cmd_eval(self, message):
"""Evaluate Python code"""
try:
formatted = message.content[6:]
print(repr(formatted))
exec_scope = {
"msg": message,
"asyncio": asyncio,
"random": __import__("random"),
**self.bot.loaded_commands,
"out": lambda content: message.reply(content, silent=True),
}
# Parse the code to detect non-async function calls
tree = ast.parse(formatted)
for node in ast.walk(tree):
if isinstance(node, ast.Call) and not isinstance(node.func, ast.Attribute):
# Check if the function is a coroutine
func_name = node.func.id
if func_name in exec_scope and asyncio.iscoroutinefunction(exec_scope[func_name]):
# Replace the call with an await expression
formatted = formatted.replace(f"{func_name}(", f"await {func_name}(")
exec(f"async def __eval():\n {formatted.replace(chr(10), chr(10) + ' ')}", exec_scope)
await exec_scope["__eval"]()
except Exception:
await message.edit(content=traceback.format_exc())
finally:
await message.delete()
async def cmd_delrecent(self, message):
"""Delete recent messages"""
try:
minutes = float(message.content.split(" ", 1)[1])
cutoff_time = datetime.datetime.now(datetime.UTC) - datetime.timedelta(minutes=minutes)
deleted = 0
async for msg in message.channel.history(limit=100):
if msg.author == self.bot.user and msg.created_at >= cutoff_time:
await msg.delete()
deleted += 1
await message.channel.send(f"Deleted {deleted} messages.", delete_after=0, silent=True)
except Exception as e:
await message.channel.send(f"Error: {e}", delete_after=0, silent=True)
async def cmd_savechannel(self, message):
"""Save all messages in a channel to a file"""
try:
messages = []
async for msg in message.channel.history(limit=None):
msg_dict = {
"id": msg.id,
"content": msg.content,
"created_at": msg.created_at.isoformat() if msg.created_at else None,
"edited_at": msg.edited_at.isoformat() if msg.edited_at else None,
"author": {
"id": msg.author.id,
"name": msg.author.name,
"discriminator": msg.author.discriminator,
"bot": msg.author.bot
} if msg.author else None,
"channel_id": msg.channel.id,
"attachments": [
{"filename": a.filename, "url": a.url} for a in msg.attachments
] if msg.attachments else [],
"embeds": [embed.to_dict() for embed in msg.embeds] if msg.embeds else [],
"reactions": [
{"emoji": str(r.emoji), "count": r.count} for r in msg.reactions
] if msg.reactions else [],
"mentions": [user.id for user in msg.mentions] if msg.mentions else [],
"role_mentions": [role.id for role in msg.role_mentions] if msg.role_mentions else [],
"pinned": msg.pinned,
"tts": msg.tts,
"type": str(msg.type),
"reference": {
"message_id": msg.reference.message_id,
"channel_id": msg.reference.channel_id,
"guild_id": msg.reference.guild_id
} if msg.reference else None,
}
messages.append(msg_dict)
filename = f"{message.channel.id}.json.gz"
os.makedirs(DOWNLOADS_DIR, exist_ok=True)
filepath = os.path.join(DOWNLOADS_DIR, filename)
with gzip.open(filepath, "wt", encoding="utf-8") as f:
json.dump(messages, f, ensure_ascii=False, indent=4)
await message.edit(content=f"Saved messages to `{filepath}`")
except Exception as e:
await message.edit(content=f"Error: {e}")

1
bot/handlers/__init__.py Normal file
View file

@ -0,0 +1 @@
# Empty init to make directory a package

View file

@ -0,0 +1,109 @@
import discord
import asyncio
from config import BLACKLISTED_USERS, BUCKET_REACT_USERS, AUTO_DELETE_USERS, SPECIAL_RESPONSES
from bot.commands.afk_commands import AfkCommands
from bot.commands.utility_commands import UtilityCommands
from bot.commands.fun_commands import FunCommands
from bot.commands.admin_commands import AdminCommands
from bot.commands.test_commands import TestCommands
class MessageHandler:
def __init__(self, bot):
self.bot = bot
# Initialize command handlers
self.afk_commands = AfkCommands(bot)
self.utility_commands = UtilityCommands(bot)
self.fun_commands = FunCommands(bot)
self.admin_commands = AdminCommands(bot)
self.test_commands = TestCommands(bot)
# Attach command handlers to the bot for easier access from tests
bot.afk_commands = self.afk_commands
bot.utility_commands = self.utility_commands
bot.fun_commands = self.fun_commands
bot.admin_commands = self.admin_commands
bot.test_commands = self.test_commands
async def handle_message(self, message):
# Handle special responses
for user_id, data in SPECIAL_RESPONSES.items():
if message.author.id == user_id and data["trigger"] in message.content:
await message.reply(data["response"])
# Handle automatic reactions
if message.channel.id in self.bot.horsin:
await message.add_reaction("🐴")
if message.author.id in BUCKET_REACT_USERS:
await message.add_reaction("🪣")
# Handle auto-delete for specific users
if message.author.id in AUTO_DELETE_USERS:
try:
await message.delete()
except:
pass
# Handle DM if in AFK mode
if isinstance(message.channel, discord.DMChannel) and message.author != self.bot.user:
await self.afk_commands.handle_afk_dm(message)
# Don't process further if the message is not from the bot user
if message.author != self.bot.user:
return
# Handle commands
await self.handle_commands(message)
async def handle_blacklist(self, message):
"""Handle blacklisted users"""
if message.author.id in BLACKLISTED_USERS:
await message.reply("no")
return True
return False
async def handle_commands(self, message):
"""Handle commands issued by the bot user"""
content = message.content
# AFK Commands
if content.startswith(".afk"):
await self.afk_commands.cmd_afk(message)
elif content.startswith(".unafk"):
await self.afk_commands.cmd_unafk(message)
# Fun Commands
elif content.startswith(".horse"):
await self.fun_commands.cmd_horse(message)
elif content.startswith(".rps "):
if not await self.handle_blacklist(message):
await self.fun_commands.cmd_rps(message)
elif content.startswith(".repeat29"):
await self.fun_commands.cmd_repeat(message)
# Utility Commands
elif content.startswith(".remindme "):
if not await self.handle_blacklist(message):
await self.utility_commands.cmd_remindme(message)
elif content.startswith(".fmt "):
await self.utility_commands.cmd_fmt(message)
elif content.startswith(".eval "):
await self.utility_commands.cmd_eval(message)
elif content.startswith(".delrecent "):
await self.utility_commands.cmd_delrecent(message)
elif content.startswith(".savechannel"):
await self.utility_commands.cmd_savechannel(message)
# Admin Commands
elif content.startswith(".addcmd "):
await self.admin_commands.cmd_addcmd(message)
elif content.startswith(".delcmd "):
await self.admin_commands.cmd_delcmd(message)
elif content.startswith(".listcmds"):
await self.admin_commands.cmd_listcmds(message)
elif content.startswith(".trackmessages"):
await self.admin_commands.cmd_trackmessages(message)
elif content.startswith(".untrackmessages"):
await self.admin_commands.cmd_untrackmessages(message)
elif content.startswith(".test"):
await self.test_commands.cmd_test(message)

View file

@ -0,0 +1,19 @@
import discord
from config import WELCOME_BACK_CHANNEL_ID
class PresenceHandler:
def __init__(self, bot):
self.bot = bot
async def handle_presence_update(self, before, after):
"""Handle user presence updates"""
if after.id == 627566973869359104:
old_status = self.bot.last_status.get(after.id, discord.Status.offline)
self.bot.last_status[after.id] = after.status
if old_status == discord.Status.offline and after.status == discord.Status.online:
channel = self.bot.get_channel(WELCOME_BACK_CHANNEL_ID)
if channel:
# Commented out for now as in original code
# await channel.send(f"[BOT] Welcome back, {after.mention}!", silent=True)
pass

View file

@ -0,0 +1,51 @@
import discord
import io
import difflib
class TrackingHandler:
def __init__(self, bot):
self.bot = bot
async def process_log_whitelist(self, message):
"""Process whitelist for logging"""
if message.author.id == 627566973869359104:
return True
return False
async def handle_message_delete(self, message):
"""Handle when messages are deleted"""
if await self.process_log_whitelist(message):
return
if message.channel.id in self.bot.tracked_channels:
member = message.author
if member != self.bot.user:
await message.channel.send(
f"<@{member.id}> deleted {message.content}",
silent=True
)
async def handle_message_edit(self, before, after):
"""Handle when messages are edited"""
if await self.process_log_whitelist(before):
return
if before.channel.id in self.bot.tracked_channels:
member = after.author
if member == self.bot.user:
return
if before.content == after.content:
return
diff = difflib.unified_diff(before.content.splitlines(), after.content.splitlines())
diff_result = '\n'.join(diff)
with io.BytesIO(diff_result.encode('utf-8')) as diff_file:
diff_file.seek(0)
await after.channel.send(
f"<@{member.id}> edited a message",
file=discord.File(diff_file, "cutie.diff"),
silent=True
)

41
bot/selfbot.py Normal file
View file

@ -0,0 +1,41 @@
import discord
from utils.storage import load_commands, load_tracked_channels
from bot.handlers.message_handler import MessageHandler
from bot.handlers.tracking_handler import TrackingHandler
from bot.handlers.presence_handler import PresenceHandler
class Selfbot(discord.Client):
def __init__(self):
super().__init__()
# State variables
self.default_status = None
self.loaded_commands = load_commands()
self.tracked_channels = load_tracked_channels()
self.last_status = {}
self.AFK_STATUS = False
self.AFK_NOTIFIED_USERS = []
self.horsin = []
# Initialize handlers
self.message_handler = MessageHandler(self)
self.tracking_handler = TrackingHandler(self)
self.presence_handler = PresenceHandler(self)
async def on_ready(self):
print(f"Logged in as {self.user}")
async def on_message(self, message):
await self.message_handler.handle_message(message)
async def on_message_delete(self, message):
await self.tracking_handler.handle_message_delete(message)
async def on_message_edit(self, before, after):
await self.tracking_handler.handle_message_edit(before, after)
async def on_presence_update(self, before, after):
await self.presence_handler.handle_presence_update(before, after)
def reload_commands(self):
"""Reload user-defined commands"""
self.loaded_commands = load_commands()