EU-Utility-Plugins-Repo/plugins/game_reader/plugin.py

262 lines
8.9 KiB
Python

"""
EU-Utility - OCR Scanner Plugin
Reads text from in-game menus using OCR.
"""
import subprocess
import platform
import tempfile
from pathlib import Path
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QTextEdit, QComboBox,
QFrame, QScrollArea, QGroupBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt6.QtGui import QPixmap, QImage
from plugins.base_plugin import BasePlugin
class OCRScannerThread(QThread):
"""Background thread for OCR scanning."""
result_ready = pyqtSignal(str)
error_occurred = pyqtSignal(str)
def __init__(self, region=None):
super().__init__()
self.region = region # (x, y, width, height)
def run(self):
"""Capture screen and perform OCR."""
try:
system = platform.system()
# Create temp file for screenshot
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
screenshot_path = tmp.name
# Capture screenshot
if system == "Windows":
# Use PowerShell to capture screen
ps_cmd = f'''
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
$bitmap = New-Object System.Drawing.Bitmap($screen.Width, $screen.Height)
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
$graphics.CopyFromScreen($screen.Location, [System.Drawing.Point]::Empty, $screen.Size)
$bitmap.Save("{screenshot_path}")
$graphics.Dispose()
$bitmap.Dispose()
'''
subprocess.run(['powershell', '-Command', ps_cmd], capture_output=True, timeout=10)
elif system == "Linux":
# Use gnome-screenshot or import
try:
subprocess.run(['gnome-screenshot', '-f', screenshot_path],
capture_output=True, timeout=10)
except:
subprocess.run(['import', '-window', 'root', screenshot_path],
capture_output=True, timeout=10)
# Perform OCR
text = self._perform_ocr(screenshot_path)
# Clean up
Path(screenshot_path).unlink(missing_ok=True)
self.result_ready.emit(text)
except Exception as e:
self.error_occurred.emit(str(e))
def _perform_ocr(self, image_path):
"""Perform OCR on image."""
try:
# Try easyocr first
import easyocr
reader = easyocr.Reader(['en'])
results = reader.readtext(image_path)
text = '\n'.join([result[1] for result in results])
return text if text else "No text detected"
except:
pass
try:
# Try pytesseract
import pytesseract
from PIL import Image
image = Image.open(image_path)
text = pytesseract.image_to_string(image)
return text if text.strip() else "No text detected"
except:
pass
return "OCR not available. Install: pip install easyocr or pytesseract"
class GameReaderPlugin(BasePlugin):
"""Read in-game menus and text using OCR."""
name = "Game Reader"
version = "1.0.0"
author = "ImpulsiveFPS"
description = "OCR scanner for in-game menus and text"
hotkey = "ctrl+shift+r" # R for Read
def initialize(self):
"""Setup game reader."""
self.scan_thread = None
self.last_result = ""
def get_ui(self):
"""Create game reader UI."""
widget = QWidget()
widget.setStyleSheet("background: transparent;")
layout = QVBoxLayout(widget)
layout.setSpacing(15)
layout.setContentsMargins(0, 0, 0, 0)
# Title
title = QLabel("📷 Game Reader (OCR)")
title.setStyleSheet("color: white; font-size: 16px; font-weight: bold;")
layout.addWidget(title)
# Info
info = QLabel("Capture in-game menus and read the text")
info.setStyleSheet("color: rgba(255, 255, 255, 150); font-size: 12px;")
layout.addWidget(info)
# Scan button
scan_btn = QPushButton("Capture Screen")
scan_btn.setStyleSheet("""
QPushButton {
background-color: #4a9eff;
color: white;
padding: 15px;
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: bold;
}
QPushButton:hover {
background-color: #5aafff;
}
QPushButton:pressed {
background-color: #3a8eef;
}
""")
scan_btn.clicked.connect(self._capture_screen)
layout.addWidget(scan_btn)
# Status
self.status_label = QLabel("Ready to capture")
self.status_label.setStyleSheet("color: #666; font-size: 11px;")
self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(self.status_label)
# Results area
results_frame = QFrame()
results_frame.setStyleSheet("""
QFrame {
background-color: rgba(0, 0, 0, 50);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 20);
}
""")
results_layout = QVBoxLayout(results_frame)
results_layout.setContentsMargins(10, 10, 10, 10)
results_label = QLabel("Captured Text:")
results_label.setStyleSheet("color: rgba(255, 255, 255, 150); font-size: 12px;")
results_layout.addWidget(results_label)
self.result_text = QTextEdit()
self.result_text.setPlaceholderText("Captured text will appear here...")
self.result_text.setStyleSheet("""
QTextEdit {
background-color: rgba(30, 30, 30, 100);
color: white;
border: none;
border-radius: 6px;
padding: 8px;
font-size: 13px;
}
""")
self.result_text.setMaximumHeight(150)
results_layout.addWidget(self.result_text)
# Copy button
copy_btn = QPushButton("Copy Text")
copy_btn.setStyleSheet("""
QPushButton {
background-color: rgba(255, 255, 255, 20);
color: white;
padding: 8px;
border: none;
border-radius: 6px;
}
QPushButton:hover {
background-color: rgba(255, 255, 255, 30);
}
""")
copy_btn.clicked.connect(self._copy_text)
results_layout.addWidget(copy_btn)
layout.addWidget(results_frame)
# Common uses
uses_label = QLabel("Common Uses:")
uses_label.setStyleSheet("color: rgba(255, 255, 255, 150); font-size: 11px; margin-top: 10px;")
layout.addWidget(uses_label)
uses_text = QLabel(
"• Read NPC dialogue\n"
"• Capture mission text\n"
"• Extract item stats\n"
"• Read shop prices"
)
uses_text.setStyleSheet("color: rgba(255, 255, 255, 100); font-size: 11px;")
layout.addWidget(uses_text)
layout.addStretch()
return widget
def _capture_screen(self):
"""Capture screen and perform OCR."""
self.status_label.setText("Capturing...")
self.status_label.setStyleSheet("color: #4a9eff;")
# Start scan thread
self.scan_thread = OCRScannerThread()
self.scan_thread.result_ready.connect(self._on_result)
self.scan_thread.error_occurred.connect(self._on_error)
self.scan_thread.start()
def _on_result(self, text):
"""Handle OCR result."""
self.result_text.setText(text)
self.last_result = text
self.status_label.setText(f"✅ Captured {len(text)} characters")
self.status_label.setStyleSheet("color: #4caf50;")
def _on_error(self, error):
"""Handle OCR error."""
self.status_label.setText(f"❌ Error: {error}")
self.status_label.setStyleSheet("color: #f44336;")
def _copy_text(self):
"""Copy text to clipboard."""
from PyQt6.QtWidgets import QApplication
clipboard = QApplication.clipboard()
clipboard.setText(self.result_text.toPlainText())
self.status_label.setText("📋 Copied to clipboard!")
def on_hotkey(self):
"""Capture on hotkey."""
self._capture_screen()