286 lines
9.0 KiB
Python
286 lines
9.0 KiB
Python
"""
|
|
EU-Utility - Chat Logger Plugin
|
|
|
|
Log and search chat messages with filters.
|
|
"""
|
|
|
|
import re
|
|
import json
|
|
from datetime import datetime, timedelta
|
|
from pathlib import Path
|
|
from collections import deque
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QPushButton, QTextEdit, QLineEdit, QComboBox,
|
|
QCheckBox, QFrame
|
|
)
|
|
from PyQt6.QtCore import Qt, QTimer
|
|
|
|
from plugins.base_plugin import BasePlugin
|
|
from core.icon_manager import get_icon_manager
|
|
|
|
|
|
class ChatLoggerPlugin(BasePlugin):
|
|
"""Log and search chat messages."""
|
|
|
|
name = "Chat Logger"
|
|
version = "1.0.0"
|
|
author = "ImpulsiveFPS"
|
|
description = "Log, search, and filter chat messages"
|
|
hotkey = "ctrl+shift+t" # T for chaT
|
|
|
|
# Chat channels
|
|
CHANNELS = {
|
|
'main': 'Main',
|
|
'society': 'Society',
|
|
'team': 'Team',
|
|
'local': 'Local',
|
|
'global': 'Global',
|
|
'trade': 'Trade',
|
|
'private': 'Private',
|
|
}
|
|
|
|
def initialize(self):
|
|
"""Setup chat logger."""
|
|
self.data_file = Path("data/chat_log.json")
|
|
self.data_file.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Keep last 10000 messages in memory
|
|
self.messages = deque(maxlen=10000)
|
|
self.filters = {
|
|
'show_main': True,
|
|
'show_society': True,
|
|
'show_team': True,
|
|
'show_local': True,
|
|
'show_global': True,
|
|
'show_trade': True,
|
|
'show_private': True,
|
|
'search_text': '',
|
|
'show_globals_only': False,
|
|
'show_loot': False,
|
|
}
|
|
|
|
self._load_recent()
|
|
|
|
def _load_recent(self):
|
|
"""Load recent messages."""
|
|
if self.data_file.exists():
|
|
try:
|
|
with open(self.data_file, 'r') as f:
|
|
data = json.load(f)
|
|
self.messages.extend(data.get('messages', [])[-1000:])
|
|
except:
|
|
pass
|
|
|
|
def _save_messages(self):
|
|
"""Save messages to file."""
|
|
# Keep last 24 hours
|
|
cutoff = (datetime.now() - timedelta(hours=24)).isoformat()
|
|
recent = [m for m in self.messages if m['time'] > cutoff]
|
|
|
|
with open(self.data_file, 'w') as f:
|
|
json.dump({'messages': recent}, f)
|
|
|
|
def get_ui(self):
|
|
"""Create plugin UI."""
|
|
widget = QWidget()
|
|
widget.setStyleSheet("background: transparent;")
|
|
layout = QVBoxLayout(widget)
|
|
layout.setSpacing(10)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
# Get icon manager
|
|
icon_mgr = get_icon_manager()
|
|
|
|
# Title with icon
|
|
title_layout = QHBoxLayout()
|
|
|
|
title_icon = QLabel()
|
|
icon_pixmap = icon_mgr.get_pixmap('message-square', size=20)
|
|
title_icon.setPixmap(icon_pixmap)
|
|
title_icon.setFixedSize(20, 20)
|
|
title_layout.addWidget(title_icon)
|
|
|
|
title = QLabel("Chat Logger")
|
|
title.setStyleSheet("color: white; font-size: 16px; font-weight: bold;")
|
|
title_layout.addWidget(title)
|
|
title_layout.addStretch()
|
|
|
|
layout.addLayout(title_layout)
|
|
|
|
# Search bar
|
|
search_layout = QHBoxLayout()
|
|
|
|
self.search_input = QLineEdit()
|
|
self.search_input.setPlaceholderText("Search messages...")
|
|
self.search_input.setStyleSheet("""
|
|
QLineEdit {
|
|
background-color: rgba(255, 255, 255, 15);
|
|
color: white;
|
|
border: 1px solid rgba(255, 255, 255, 30);
|
|
border-radius: 6px;
|
|
padding: 8px;
|
|
}
|
|
""")
|
|
self.search_input.textChanged.connect(self._update_filter)
|
|
search_layout.addWidget(self.search_input)
|
|
|
|
search_btn = QPushButton("🔍")
|
|
search_btn.setFixedSize(32, 32)
|
|
search_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: rgba(255, 255, 255, 15);
|
|
border: none;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: rgba(255, 255, 255, 30);
|
|
}
|
|
""")
|
|
search_layout.addWidget(search_btn)
|
|
|
|
layout.addLayout(search_layout)
|
|
|
|
# Filters
|
|
filters_frame = QFrame()
|
|
filters_frame.setStyleSheet("""
|
|
QFrame {
|
|
background-color: rgba(0, 0, 0, 50);
|
|
border-radius: 8px;
|
|
border: 1px solid rgba(255, 255, 255, 20);
|
|
}
|
|
""")
|
|
filters_layout = QHBoxLayout(filters_frame)
|
|
filters_layout.setContentsMargins(10, 6, 10, 6)
|
|
|
|
# Channel filters
|
|
self.filter_checks = {}
|
|
for channel_id, channel_name in self.CHANNELS.items():
|
|
cb = QCheckBox(channel_name)
|
|
cb.setChecked(True)
|
|
cb.setStyleSheet("color: rgba(255, 255, 255, 180); font-size: 10px;")
|
|
cb.stateChanged.connect(self._update_filter)
|
|
self.filter_checks[channel_id] = cb
|
|
filters_layout.addWidget(cb)
|
|
|
|
filters_layout.addStretch()
|
|
layout.addWidget(filters_frame)
|
|
|
|
# Chat display
|
|
self.chat_display = QTextEdit()
|
|
self.chat_display.setReadOnly(True)
|
|
self.chat_display.setStyleSheet("""
|
|
QTextEdit {
|
|
background-color: rgba(20, 25, 35, 150);
|
|
color: white;
|
|
border: 1px solid rgba(255, 255, 255, 20);
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
font-family: Consolas, monospace;
|
|
font-size: 11px;
|
|
}
|
|
""")
|
|
layout.addWidget(self.chat_display)
|
|
|
|
# Stats
|
|
self.stats_label = QLabel("Messages: 0")
|
|
self.stats_label.setStyleSheet("color: rgba(255, 255, 255, 100); font-size: 10px;")
|
|
layout.addWidget(self.stats_label)
|
|
|
|
# Refresh display
|
|
self._refresh_display()
|
|
|
|
return widget
|
|
|
|
def _update_filter(self):
|
|
"""Update filter settings."""
|
|
self.filters['search_text'] = self.search_input.text().lower()
|
|
|
|
for channel_id, cb in self.filter_checks.items():
|
|
self.filters[f'show_{channel_id}'] = cb.isChecked()
|
|
|
|
self._refresh_display()
|
|
|
|
def _refresh_display(self):
|
|
"""Refresh chat display."""
|
|
html = []
|
|
|
|
for msg in reversed(self.messages):
|
|
# Apply filters
|
|
channel = msg.get('channel', 'main')
|
|
if not self.filters.get(f'show_{channel}', True):
|
|
continue
|
|
|
|
text = msg.get('text', '')
|
|
if self.filters['search_text']:
|
|
if self.filters['search_text'] not in text.lower():
|
|
continue
|
|
|
|
# Format message
|
|
time_str = msg['time'][11:16] if msg['time'] else '--:--'
|
|
author = msg.get('author', 'Unknown')
|
|
|
|
# Color by channel
|
|
colors = {
|
|
'main': '#ffffff',
|
|
'society': '#9c27b0',
|
|
'team': '#4caf50',
|
|
'local': '#ffc107',
|
|
'global': '#f44336',
|
|
'trade': '#ff9800',
|
|
'private': '#00bcd4',
|
|
}
|
|
color = colors.get(channel, '#ffffff')
|
|
|
|
html.append(f'''
|
|
<div style="margin: 2px 0;">
|
|
<span style="color: #666;">[{time_str}]</span>
|
|
<span style="color: {color}; font-weight: bold;">{author}:</span>
|
|
<span style="color: #ccc;">{text}</span>
|
|
</div>
|
|
''')
|
|
|
|
self.chat_display.setHtml(''.join(html[:100])) # Show last 100
|
|
self.stats_label.setText(f"Messages: {len(self.messages)}")
|
|
|
|
def parse_chat_message(self, message, channel='main', author='Unknown'):
|
|
"""Parse and log chat message."""
|
|
entry = {
|
|
'time': datetime.now().isoformat(),
|
|
'channel': channel,
|
|
'author': author,
|
|
'text': message,
|
|
}
|
|
|
|
self.messages.append(entry)
|
|
self._refresh_display()
|
|
|
|
# Auto-save periodically
|
|
if len(self.messages) % 100 == 0:
|
|
self._save_messages()
|
|
|
|
def search(self, query):
|
|
"""Search chat history."""
|
|
results = []
|
|
query_lower = query.lower()
|
|
|
|
for msg in self.messages:
|
|
if query_lower in msg.get('text', '').lower():
|
|
results.append(msg)
|
|
|
|
return results
|
|
|
|
def get_globals(self):
|
|
"""Get global messages."""
|
|
return [m for m in self.messages if m.get('channel') == 'global']
|
|
|
|
def get_loot_messages(self):
|
|
"""Get loot-related messages."""
|
|
loot_keywords = ['received', 'loot', 'item', 'ped']
|
|
return [
|
|
m for m in self.messages
|
|
if any(kw in m.get('text', '').lower() for kw in loot_keywords)
|
|
]
|