worky
This commit is contained in:
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM python:3.10-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . .
|
||||
CMD ["python", "bot.py"]
|
||||
29
bot.py
Normal file
29
bot.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import discord
|
||||
import asyncio
|
||||
from discord.ext import commands
|
||||
from config import Config
|
||||
|
||||
class RealBot(commands.Bot):
|
||||
def __init__(self):
|
||||
intents = discord.Intents.default()
|
||||
intents.messages = True
|
||||
intents.message_content = True
|
||||
intents.members = True
|
||||
super().__init__(command_prefix="!", intents=intents)
|
||||
|
||||
async def setup_hook(self):
|
||||
# Loads the extension from the 'cogs' folder
|
||||
# Note the dot notation: cogs.logger
|
||||
await self.load_extension("cogs.logger")
|
||||
print("Logger extension loaded.")
|
||||
|
||||
async def on_ready(self):
|
||||
print(f"Logged in as {self.user} (ID: {self.user.id})")
|
||||
print("---------------------------------------------")
|
||||
|
||||
if __name__ == "__main__":
|
||||
bot = RealBot()
|
||||
try:
|
||||
bot.run(Config.BOT_TOKEN)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
71
cogs/logger.py
Normal file
71
cogs/logger.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from config import Config
|
||||
import utils
|
||||
|
||||
class ChatLogger(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message_delete(self, message: discord.Message):
|
||||
# 1. Validation
|
||||
if message.author.bot: return
|
||||
|
||||
# 2. Build Embed
|
||||
embed = discord.Embed(
|
||||
description=f"**Message sent by {message.author.mention} was deleted**",
|
||||
color=Config.COLOR_DELETE,
|
||||
timestamp=utils.get_timestamp()
|
||||
)
|
||||
|
||||
embed.set_author(
|
||||
name=f"{message.author}",
|
||||
icon_url=message.author.avatar.url if message.author.avatar else None
|
||||
)
|
||||
|
||||
content = message.content if message.content else "[No Text Content]"
|
||||
embed.add_field(name="Deleted Text:", value=utils.truncate(content), inline=False)
|
||||
|
||||
# 3. Secure Image Handling
|
||||
if message.attachments:
|
||||
links = [f"[{att.filename}]({att.proxy_url})" for att in message.attachments]
|
||||
embed.add_field(name="Evidence:", value="\n".join(links), inline=False)
|
||||
embed.set_image(url=message.attachments[0].proxy_url)
|
||||
|
||||
embed.set_footer(text="Caught in 4K") # Optional flavor text
|
||||
|
||||
# 4. Send to the SAME channel
|
||||
await message.channel.send(embed=embed)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message_edit(self, before: discord.Message, after: discord.Message):
|
||||
# 1. Validation
|
||||
if before.author.bot: return
|
||||
if before.content == after.content: return
|
||||
|
||||
# 2. Build Embed
|
||||
embed = discord.Embed(
|
||||
description=f"**Message edited by {before.author.mention}** [Jump to Message]({after.jump_url})",
|
||||
color=Config.COLOR_EDIT,
|
||||
timestamp=utils.get_timestamp()
|
||||
)
|
||||
|
||||
embed.set_author(
|
||||
name=f"{before.author}",
|
||||
icon_url=before.author.avatar.url if before.author.avatar else None
|
||||
)
|
||||
|
||||
original = before.content if before.content else "[No Text Content]"
|
||||
# We don't necessarily need the "Edited to" field here since the
|
||||
# actual edited message is visible right above this log, but it's good for history.
|
||||
|
||||
embed.add_field(name="Original:", value=utils.truncate(original), inline=False)
|
||||
|
||||
embed.set_footer(text="Edit History")
|
||||
|
||||
# 3. Send to the SAME channel
|
||||
await before.channel.send(embed=embed)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(ChatLogger(bot))
|
||||
18
config.py
Normal file
18
config.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
import discord
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load .env file (if it exists) for local testing
|
||||
load_dotenv()
|
||||
|
||||
class Config:
|
||||
# Secrets
|
||||
BOT_TOKEN = os.getenv("DISCORD_TOKEN", "YOUR_FALLBACK_TOKEN_HERE")
|
||||
|
||||
# Settings
|
||||
LOG_CHANNEL_NAME = "real-chat-logs"
|
||||
EMBED_LIMIT = 1000
|
||||
|
||||
# Colors
|
||||
COLOR_DELETE = discord.Color.red()
|
||||
COLOR_EDIT = discord.Color.orange()
|
||||
7
docker-compose.yml
Normal file
7
docker-compose.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
discord-bot:
|
||||
build: .
|
||||
container_name: real_chat_bot
|
||||
restart: always # If the bot crashes or server reboots, this auto-restarts it
|
||||
environment:
|
||||
- DISCORD_TOKEN=""
|
||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
discord.py
|
||||
python-dotenv
|
||||
12
utils.py
Normal file
12
utils.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import datetime
|
||||
from config import Config
|
||||
|
||||
def truncate(text: str, limit: int = Config.EMBED_LIMIT) -> str:
|
||||
"""Truncates text to ensure it fits in an Embed field."""
|
||||
if len(text) > limit:
|
||||
return text[:limit] + "..."
|
||||
return text
|
||||
|
||||
def get_timestamp():
|
||||
"""Returns the current timestamp."""
|
||||
return datetime.datetime.now()
|
||||
Reference in New Issue
Block a user