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> 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_ – 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)