Mosswart lurker
This commit is contained in:
commit
ec6b814ac8
1 changed files with 398 additions and 0 deletions
398
bottenstats.py
Normal file
398
bottenstats.py
Normal file
|
|
@ -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: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)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue