398 lines
7.5 KiB
Python
398 lines
7.5 KiB
Python
import discord
|
||
|
||
import asyncio
|
||
|
||
import shutil
|
||
|
||
import os
|
||
|
||
import re
|
||
|
||
import json
|
||
|
||
from datetime import datetime, timedelta
|
||
|
||
|
||
|
||
# === CONFIGURATION ===
|
||
|
||
TOKEN = 'MTM0OTgwNTE1NzY5MjYwNDUwNg.Gv_jgN.GyvpdRHS95UrzCHapfHm94_4bzvIS1g5g9uq54'
|
||
|
||
CHANNEL_ID_ACLOG = 1349649482786275328
|
||
|
||
CHANNEL_ID_COMMON_RARES = 1355328792184226014
|
||
|
||
CHANNEL_ID_GREAT_RARES = 1353676584334131211
|
||
|
||
COMMON_RARE_KEYWORDS = ["Crystal", "Jewel", "Pearl", "Elixir", "Kit"]
|
||
|
||
LOG_FILE = 'C:/Users/acbot/Documents/Decal Plugins/UtilityBelt/Coldeve/Dunking Rares/chat.txt'
|
||
|
||
TEMP_FILE = 'C:/Users/acbot/Documents/bot/chat_copy.txt'
|
||
|
||
STATS_FILE = 'C:/Users/acbot/Documents/bot/rares_stats.json'
|
||
|
||
|
||
|
||
# === DISCORD SETUP ===
|
||
|
||
intents = discord.Intents.default()
|
||
|
||
intents.guilds = True
|
||
|
||
intents.messages = True
|
||
|
||
intents.message_content = True
|
||
|
||
client = discord.Client(intents=intents)
|
||
|
||
|
||
|
||
# === STATS STORAGE ===
|
||
|
||
rares_stats = {}
|
||
|
||
|
||
|
||
def load_stats():
|
||
|
||
global rares_stats
|
||
|
||
if os.path.exists(STATS_FILE):
|
||
|
||
with open(STATS_FILE, 'r') as f:
|
||
|
||
rares_stats = json.load(f)
|
||
|
||
else:
|
||
|
||
rares_stats = {}
|
||
|
||
|
||
|
||
def save_stats():
|
||
try:
|
||
with open(STATS_FILE, 'w') as f:
|
||
json.dump(rares_stats, f, indent=2)
|
||
print(f"✅ Stats saved to: {STATS_FILE}")
|
||
except Exception as e:
|
||
print(f"❌ Failed to save stats: {e}")
|
||
|
||
# === PARSE ===
|
||
|
||
def parse_line(line):
|
||
|
||
match = re.search(r'^(.*?)\|.*?<Tell:IIDString:\d+:(.+?)>.+?<\\Tell> says, "(.*?)"', line)
|
||
|
||
if match:
|
||
|
||
timestamp_full = match.group(1)
|
||
|
||
name = match.group(2)
|
||
|
||
message = match.group(3)
|
||
|
||
time_match = re.search(r'T(\d{2}:\d{2}:\d{2})', timestamp_full)
|
||
|
||
if time_match:
|
||
|
||
short_time = time_match.group(1)
|
||
|
||
else:
|
||
|
||
short_time = "Unknown"
|
||
|
||
return short_time, name, message
|
||
|
||
return None
|
||
|
||
|
||
|
||
def track_rare(name, rare_type):
|
||
print(f"Tracking Rare: {name} found {rare_type}")
|
||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
|
||
|
||
if name not in rares_stats:
|
||
|
||
rares_stats[name] = {"total": 0, "rares": []}
|
||
|
||
rares_stats[name]["total"] += 1
|
||
|
||
rares_stats[name]["rares"].append({"type": rare_type, "timestamp": timestamp})
|
||
|
||
save_stats()
|
||
|
||
|
||
|
||
def summary_for_range(label, days):
|
||
|
||
cutoff = datetime.now() - timedelta(days=days)
|
||
|
||
output = f"**Rare Summary – {label}**\n"
|
||
|
||
found_any = False
|
||
|
||
for name, data in rares_stats.items():
|
||
|
||
count = 0
|
||
|
||
for r in data['rares']:
|
||
|
||
try:
|
||
|
||
ts = datetime.strptime(r['timestamp'], "%Y-%m-%d %H:%M")
|
||
|
||
if ts >= cutoff:
|
||
|
||
count += 1
|
||
|
||
except:
|
||
|
||
continue
|
||
|
||
if count > 0:
|
||
|
||
output += f"{name} – {count}\n"
|
||
|
||
found_any = True
|
||
|
||
return output if found_any else f"No rares found in the last {label.lower()}."
|
||
|
||
|
||
|
||
# === BOT EVENTS ===
|
||
|
||
@client.event
|
||
|
||
async def on_ready():
|
||
|
||
print(f'✅ Inloggad som {client.user}')
|
||
|
||
load_stats()
|
||
|
||
ch_aclog = client.get_channel(CHANNEL_ID_ACLOG)
|
||
|
||
ch_common = client.get_channel(CHANNEL_ID_COMMON_RARES)
|
||
|
||
ch_great = client.get_channel(CHANNEL_ID_GREAT_RARES)
|
||
|
||
if not all([ch_aclog, ch_common, ch_great]):
|
||
|
||
print("❌ Kunde inte hitta alla kanaler.")
|
||
|
||
await client.close()
|
||
|
||
return
|
||
|
||
asyncio.create_task(monitor_file(ch_aclog, ch_common, ch_great))
|
||
|
||
|
||
|
||
@client.event
|
||
|
||
async def on_message(message):
|
||
|
||
if message.author == client.user:
|
||
|
||
return
|
||
|
||
|
||
|
||
content = message.content.lower()
|
||
|
||
|
||
|
||
if content.startswith('!help'):
|
||
|
||
reply = (
|
||
|
||
"**Available Commands:**\n"
|
||
|
||
"!stats – Show total rare count per player\n"
|
||
|
||
"!stats_<name> – Show rare types and timestamps for a player\n"
|
||
|
||
"!top – Show top 3 players with most rares\n"
|
||
|
||
"!daily – Rares found in the last 24h\n"
|
||
|
||
"!weekly – Rares found in the last 7 days\n"
|
||
|
||
"!monthly – Rares found in the last 30 days\n"
|
||
|
||
"!yearly – Rares found in the last 365 days"
|
||
|
||
)
|
||
|
||
await message.channel.send(reply)
|
||
|
||
|
||
|
||
elif content.startswith('!stats_'):
|
||
|
||
name = message.content[len('!stats_'):].strip()
|
||
|
||
if name in rares_stats:
|
||
|
||
reply = f"**{name}** has found the following rares:\n"
|
||
|
||
for r in rares_stats[name]['rares']:
|
||
|
||
reply += f"• {r['type']} – {r['timestamp']}\n"
|
||
|
||
else:
|
||
|
||
reply = f"No rares found for {name}."
|
||
|
||
await message.channel.send(reply)
|
||
|
||
|
||
|
||
elif content.startswith('!stats'):
|
||
|
||
if not rares_stats:
|
||
|
||
await message.channel.send("No rares recorded yet.")
|
||
|
||
return
|
||
|
||
reply = "**Rares per player:**\n"
|
||
|
||
for name, data in rares_stats.items():
|
||
|
||
reply += f"{name} – {data['total']} rares\n"
|
||
|
||
await message.channel.send(reply)
|
||
|
||
|
||
|
||
elif content.startswith('!top'):
|
||
|
||
top = sorted(rares_stats.items(), key=lambda x: x[1]['total'], reverse=True)[:3]
|
||
|
||
if not top:
|
||
|
||
await message.channel.send("No rare data yet.")
|
||
|
||
return
|
||
|
||
reply = "**Top Rare Hunters:**\n"
|
||
|
||
for i, (name, data) in enumerate(top, 1):
|
||
|
||
reply += f"{i}. {name} – {data['total']} rares\n"
|
||
|
||
await message.channel.send(reply)
|
||
|
||
|
||
|
||
elif content.startswith('!daily'):
|
||
|
||
await message.channel.send(summary_for_range("Daily", 1))
|
||
|
||
|
||
|
||
elif content.startswith('!weekly'):
|
||
|
||
await message.channel.send(summary_for_range("Weekly", 7))
|
||
|
||
|
||
|
||
elif content.startswith('!monthly'):
|
||
|
||
await message.channel.send(summary_for_range("Monthly", 30))
|
||
|
||
|
||
|
||
elif content.startswith('!yearly'):
|
||
|
||
await message.channel.send(summary_for_range("Yearly", 365))
|
||
|
||
|
||
|
||
# === FILE MONITORING ===
|
||
|
||
async def monitor_file(ch_aclog, ch_common, ch_great):
|
||
|
||
last_position = None
|
||
|
||
while True:
|
||
|
||
try:
|
||
|
||
shutil.copyfile(LOG_FILE, TEMP_FILE)
|
||
|
||
with open(TEMP_FILE, 'r', encoding='utf-8') as file:
|
||
|
||
if last_position is None:
|
||
|
||
file.seek(0, 2)
|
||
|
||
last_position = file.tell()
|
||
|
||
else:
|
||
|
||
file.seek(last_position)
|
||
|
||
new_lines = file.readlines()
|
||
|
||
last_position = file.tell()
|
||
|
||
|
||
|
||
for line in new_lines:
|
||
|
||
line = line.strip()
|
||
|
||
if line:
|
||
|
||
parsed = parse_line(line)
|
||
|
||
if parsed:
|
||
|
||
timestamp, name, message = parsed
|
||
|
||
embed = discord.Embed(
|
||
|
||
title=timestamp,
|
||
|
||
description=f'**{name}**\n"{message}"',
|
||
|
||
color=discord.Color.green()
|
||
|
||
)
|
||
|
||
|
||
|
||
if "has discovered the" in message:
|
||
|
||
if any(k in message for k in COMMON_RARE_KEYWORDS) and "Frore Crystal" not in message:
|
||
|
||
await ch_common.send(embed=embed)
|
||
|
||
else:
|
||
|
||
await ch_great.send(embed=embed)
|
||
|
||
rare_name_match = re.search(r'has discovered the (.+?)!', message)
|
||
|
||
if rare_name_match:
|
||
|
||
rare_name = rare_name_match.group(1)
|
||
|
||
track_rare(name, rare_name)
|
||
|
||
else:
|
||
|
||
await ch_aclog.send(embed=embed)
|
||
|
||
except Exception as e:
|
||
|
||
print(f"⚠️ Fel: {e}")
|
||
|
||
await asyncio.sleep(1)
|
||
|
||
|
||
|
||
client.run(TOKEN)
|
||
|