commit ec6b814ac86d84243d7a6ecc2710ed827e7105a5 Author: erikn Date: Sat Apr 12 23:52:35 2025 +0200 Mosswart lurker diff --git a/bottenstats.py b/bottenstats.py new file mode 100644 index 0000000..257dd15 --- /dev/null +++ b/bottenstats.py @@ -0,0 +1,398 @@ +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) +