Commit 0cf25b1c authored by Bhavani's avatar Bhavani
Browse files

Merge branch 'updated_discord_history_bot' into 'master'

Updated Discord bot with per-message JSON logging and reaction history

See merge request !1
parents 73fd7161 7bdadb3d
import discord
import os
from dotenv import load_dotenv
import re
intents = discord.Intents.default()
intents.message_content = True
intents.guilds = True
intents.messages = True
intents.reactions = True
client = discord.Client(intents=intents)
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
URL_REGEX = r'(https?://\S+)' # URL regex
@client.event
async def on_ready():
print(f'Bot successfully logged on as {client.user} (ID: {client.user.id})')
#maybe DB init here
@client.event
async def on_message(message):
if message.author == client.user:
return
message_data = {
"content": message.content,
"author_name": str(message.author),
"author_id": message.author.id,
"channel_id": message.channel.id,
"server_id": message.guild.id if message.guild else "DM",
"timestamp": message.created_at.isoformat()
}
print(f'{message.author} said: {message_data["content"]}')
found_links = re.findall(URL_REGEX, message.content)
if found_links:
print(f'LINKS FOUND: {message.author} posted {len(found_links)} link(s): {", ".join(found_links)}')
if message.attachments:
for attachment in message.attachments:
log_entry = {
"filename": attachment.filename,
"url": attachment.url,
"content_type": attachment.content_type,
"size_bytes": attachment.size
}
print(f'ATTACHMENT: {message.author} attached "{log_entry["filename"]}" (Type: {log_entry["content_type"]}) at URL: {log_entry["url"]}')
if log_entry["content_type"] and log_entry["content_type"].startswith('image/'):
print(" -> Type: Image.")
elif log_entry["content_type"] and log_entry["content_type"].startswith('video/'):
print(" -> Type: Video.")
if message.embeds:
for embed in message.embeds:
url = embed.url if embed.url else "N/A"
title = embed.title if embed.title else "N/A"
print(f'EMBED: {message.author} triggered an embed.')
print(f' -> Title: "{title}", URL: {url}')
# Wenn das Embed ein Bild oder Video enthält, findest du die Daten hier:
if embed.image and embed.image.url:
print(f' -> Embedded Image URL: {embed.image.url}')
if embed.video and embed.video.url:
print(f' -> Embedded Video URL: {embed.video.url}')
@client.event
async def on_reaction_add(reaction, user):
if user == client.user:
return
log_reaction_change(
message_id=reaction.message.id,
emoji=str(reaction.emoji),
user_id=user.id,
action="ADDED"
)
@client.event
async def on_reaction_remove(reaction, user):
print(f'{user} said: {reaction}')
if user == client.user:
return
log_reaction_change(
message_id=reaction.message.id,
emoji=str(reaction.emoji),
user_id=user.id,
action="REMOVED"
)
def log_reaction_change(message_id, emoji, user_id, action):
print(f'Logging {action} on {message_id} with emoji {emoji}')
client.run(TOKEN)
\ No newline at end of file
import discord
import os
import json
import re
from pathlib import Path
import asyncio
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.environ.get('DISCORD_TOKEN')
intents = discord.Intents.default()
intents.message_content = True
intents.guilds = True
intents.messages = True
intents.reactions = True
intents.members = True
client = discord.Client(intents=intents)
DATA_DIR = Path("logs")
DATA_DIR.mkdir(exist_ok=True)
MESSAGES_DIR = DATA_DIR / "messages"
MESSAGES_DIR.mkdir(exist_ok=True)
URL_REGEX = r'(https?://\S+)'
def _safe_filename(s: str) -> str:
return re.sub(r"[^0-9A-Za-z._-]", "_", s)
def _atomic_write_json(data: dict, dest: Path) -> None:
import tempfile, os, json
dest.parent.mkdir(parents=True, exist_ok=True)
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False, dir=str(dest.parent), suffix=".json") as tmp:
json.dump(data, tmp, ensure_ascii=False, indent=2)
tmp_name = tmp.name
os.replace(tmp_name, dest)
async def save_json_file_async(data: dict, dest: Path) -> None:
loop = asyncio.get_running_loop()
await loop.run_in_executor(None, _atomic_write_json, data, dest)
# === Bot startup: fetch history ===
@client.event
async def on_ready():
print(f'✅ Bot logged in as {client.user} (ID: {client.user.id})')
for guild in client.guilds:
print(f'\n📜 Fetching message history from server: {guild.name}')
for channel in guild.text_channels:
try:
print(f' -> Channel: #{channel.name}')
async for message in channel.history(limit=None):
ts_safe = _safe_filename(message.created_at.isoformat())
message_file = MESSAGES_DIR / f"{message.id}_{ts_safe}.json"
if message_file.exists():
with open(message_file, 'r', encoding='utf-8') as f:
message_data = json.load(f)
else:
message_data = {
"message_id": str(message.id),
"user_id": str(message.author.id),
"text": message.content,
"reactions_history": [],
"links": re.findall(URL_REGEX, message.content)
}
# Ensure reactions_history exists
message_data.setdefault("reactions_history", [])
current_emojis = [str(reaction.emoji) for reaction in message.reactions]
message_data["reactions_history"].append({
"timestamp": str(message.created_at.isoformat()),
"emojis": current_emojis
})
await save_json_file_async(message_data, message_file)
except discord.Forbidden:
print(f' ⚠️ No permission to read #{channel.name}')
except discord.HTTPException as e:
print(f' ❌ Failed to fetch history in #{channel.name}: {e}')
print("✅ Finished loading message history.\n")
# === New message event ===
@client.event
async def on_message(message: discord.Message):
if message.author == client.user:
return
ts_safe = _safe_filename(message.created_at.isoformat())
message_file = MESSAGES_DIR / f"{message.id}_{ts_safe}.json"
message_data = {
"message_id": str(message.id),
"user_id": str(message.author.id),
"text": message.content,
"reactions_history": [],
"links": re.findall(URL_REGEX, message.content)
}
await save_json_file_async(message_data, message_file)
print(f'💬 {message.author} said: {message.content} (saved to {message_file})')
# === Reaction events ===
async def update_reaction_history(message_id: str, emoji: str, user_id: str, action: str, timestamp: str):
# Find the message file (support historic messages)
message_files = list(MESSAGES_DIR.glob(f"{message_id}_*.json"))
if not message_files:
return
message_file = message_files[0]
with open(message_file, 'r', encoding='utf-8') as f:
message_data = json.load(f)
message_data.setdefault("reactions_history", [])
entry = {
"timestamp": timestamp,
"emoji": emoji,
"user_id": user_id,
"action": action
}
message_data["reactions_history"].append(entry)
await save_json_file_async(message_data, message_file)
@client.event
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
ts = str(payload.timestamp) if hasattr(payload, 'timestamp') else ""
await update_reaction_history(str(payload.message_id), str(payload.emoji), str(payload.user_id), "ADDED", ts)
print(f'🎭 Reaction added logged for message {payload.message_id}')
@client.event
async def on_raw_reaction_remove(payload: discord.RawReactionActionEvent):
ts = str(payload.timestamp) if hasattr(payload, 'timestamp') else ""
await update_reaction_history(str(payload.message_id), str(payload.emoji), str(payload.user_id), "REMOVED", ts)
print(f'🎭 Reaction removed logged for message {payload.message_id}')
client.run(TOKEN)
{
"message_id": "1430515722689187972",
"user_id": "626398752269139984",
"text": "hello",
"reactions_history": [
{
"timestamp": "2025-10-22T11:18:45.986000+00:00",
"emojis": [
"👍",
"👎"
]
},
{
"timestamp": "2025-10-22T11:18:45.986000+00:00",
"emojis": [
"👍",
"👎"
]
},
{
"timestamp": "2025-10-22T11:18:45.986000+00:00",
"emojis": [
"👍",
"👎"
]
},
{
"timestamp": "2025-10-22T11:18:45.986000+00:00",
"emojis": [
"👍",
"👎"
]
},
{
"timestamp": "2025-10-22T11:18:45.986000+00:00",
"emojis": [
"👍",
"👎"
]
},
{
"timestamp": "2025-10-22T11:18:45.986000+00:00",
"emojis": [
"👍",
"👎"
]
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1431028891694137366",
"user_id": "1431026396989231134",
"text": "",
"reactions_history": [
{
"timestamp": "2025-10-23T21:17:55.011000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-23T21:17:55.011000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-23T21:17:55.011000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-23T21:17:55.011000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-23T21:17:55.011000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-23T21:17:55.011000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1431935814727893015",
"user_id": "626398752269139984",
"text": "Bellingcat #latest-resources",
"reactions_history": [
{
"timestamp": "2025-10-26T09:21:42.312000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:21:42.312000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:21:42.312000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:21:42.312000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:21:42.312000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:21:42.312000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1431940056796500038",
"user_id": "317309881163972608",
"text": "",
"reactions_history": [
{
"timestamp": "2025-10-26T09:38:33.700000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:38:33.700000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:38:33.700000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:38:33.700000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:38:33.700000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-26T09:38:33.700000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432657771081502770",
"user_id": "1432408692665356319",
"text": "",
"reactions_history": [
{
"timestamp": "2025-10-28T09:10:30.120000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:30.120000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:30.120000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:30.120000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:30.120000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:30.120000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432657826882523278",
"user_id": "317309881163972608",
"text": "asdfasdf",
"reactions_history": [
{
"timestamp": "2025-10-28T09:10:43.424000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:43.424000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:43.424000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:43.424000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:43.424000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:10:43.424000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432657904036479140",
"user_id": "317309881163972608",
"text": "TEST TEST-SErver",
"reactions_history": [
{
"timestamp": "2025-10-28T09:11:01.819000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:11:01.819000+00:00",
"emojis": []
},
{
"timestamp": "",
"emoji": "👍",
"user_id": "1427963581797761105",
"action": "ADDED"
},
{
"timestamp": "",
"emoji": "👍",
"user_id": "1427963581797761105",
"action": "REMOVED"
},
{
"timestamp": "2025-10-28T09:11:01.819000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:11:01.819000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:11:01.819000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:11:01.819000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432659469103271967",
"user_id": "626398752269139984",
"text": "DennisL1VE #announcement",
"reactions_history": [
{
"timestamp": "2025-10-28T09:17:14.960000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:17:14.960000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:17:14.960000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:17:14.960000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:17:14.960000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:17:14.960000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432659913523462196",
"user_id": "317309881163972608",
"text": "test",
"reactions_history": [
{
"timestamp": "2025-10-28T09:19:00.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:19:00.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:19:00.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:19:00.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:19:00.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:19:00.918000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432659932901015583",
"user_id": "317309881163972608",
"text": "test",
"reactions_history": [
{
"timestamp": "2025-10-28T09:19:05.538000+00:00",
"emojis": [
"👍"
]
},
{
"timestamp": "2025-10-28T09:19:05.538000+00:00",
"emojis": [
"👍"
]
},
{
"timestamp": "2025-10-28T09:19:05.538000+00:00",
"emojis": [
"👍"
]
},
{
"timestamp": "2025-10-28T09:19:05.538000+00:00",
"emojis": [
"👍"
]
},
{
"timestamp": "2025-10-28T09:19:05.538000+00:00",
"emojis": [
"👍"
]
},
{
"timestamp": "2025-10-28T09:19:05.538000+00:00",
"emojis": [
"👍"
]
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432660172827787294",
"user_id": "1432659370478403614",
"text": "TEST MIRROR",
"reactions_history": [
{
"timestamp": "2025-10-28T09:20:02.741000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:20:02.741000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:20:02.741000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:20:02.741000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:20:02.741000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:20:02.741000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432661128525254698",
"user_id": "626398752269139984",
"text": "Faytuks News [OSINT] #breaking-news",
"reactions_history": [
{
"timestamp": "2025-10-28T09:23:50.597000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:23:50.597000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:23:50.597000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:23:50.597000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:23:50.597000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:23:50.597000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432661366107410546",
"user_id": "626398752269139984",
"text": "GlobalNews.Watch #🚨war🚨newsline",
"reactions_history": [
{
"timestamp": "2025-10-28T09:24:47.241000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:47.241000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:47.241000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:47.241000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:47.241000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:47.241000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432661419278733388",
"user_id": "626398752269139984",
"text": "Real Time News #weekly-news-recap-📰",
"reactions_history": [
{
"timestamp": "2025-10-28T09:24:59.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:59.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:59.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:59.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:59.918000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:24:59.918000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432661422524989553",
"user_id": "626398752269139984",
"text": "GlobalNews.Watch #🌐newsline",
"reactions_history": [
{
"timestamp": "2025-10-28T09:25:00.692000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:00.692000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:00.692000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:00.692000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:00.692000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:00.692000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432661589068091432",
"user_id": "626398752269139984",
"text": "Bellingcat #latest-research",
"reactions_history": [
{
"timestamp": "2025-10-28T09:25:40.399000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:40.399000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:40.399000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:40.399000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:40.399000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:40.399000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
{
"message_id": "1432661633934823525",
"user_id": "626398752269139984",
"text": "Bellingcat #latest-resources",
"reactions_history": [
{
"timestamp": "2025-10-28T09:25:51.096000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:51.096000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:51.096000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:51.096000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:51.096000+00:00",
"emojis": []
},
{
"timestamp": "2025-10-28T09:25:51.096000+00:00",
"emojis": []
}
],
"links": []
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment