Ich hab mal ein Dungeon Tool Overlay gemacht in Python, welcher mit der Method Seite kommuniziert und es ermöglicht die Routen über das Game zu legen.
[Overlay] Hotkeys aktiv:
F8 → Seite auf Deutsch übersetzen
F9 → Beenden
F10 → Klickdurchlässigkeit umschalten
F11 → Transparenz erhöhen/verringern
Oben in der Leiste → steht immer der Dungeon Name und dort kann man sich kompakte Informationen holen zu den Dungeon und Bossen in Deutsch, sobald man die Seite zu dem Dungeon geladen hat.
Dazu hatte ich HTML-Dateien erstellt.
Das braucht PYTHON damit der Code funktioniert:
Code:
pip install PyQt5 PyQtWebEngine keyboard
Code:
import sys
import threading
import ctypes
import os
import re
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
import keyboard
class GameOverlay(QMainWindow):
def __init__(self, url):
super().__init__()
# --- Fenster-Konfiguration ---
self.setWindowTitle("Overlay Browser")
self.setGeometry(300, 200, 1000, 800)
self.setWindowOpacity(1)
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Window)
# Zustände
self.click_through = False
self.opacity = 1
self.scroll_offset = 388
self.current_dungeon_name = ""
# --- Webansicht ---
self.browser = QWebEngineView()
self.browser.setUrl(QUrl(url))
self.browser.setZoomFactor(1.0)
self.browser.loadFinished.connect(self.scroll_to_position)
self.browser.urlChanged.connect(self.update_info_button_text)
# --- Info-Button (volle Breite) ---
self.info_button = QPushButton()
self.info_button.setFixedHeight(40)
self.info_button.setStyleSheet("""
QPushButton {
background-color: rgba(40, 40, 40, 160);
color: white;
border: none;
font-size: 18px;
font-weight: bold;
}
QPushButton:hover {
background-color: rgba(70, 70, 70, 200);
}
""")
self.info_button.clicked.connect(self.show_info_window)
# --- Layouts ---
layout = QVBoxLayout()
layout.addWidget(self.info_button)
layout.addWidget(self.browser)
layout.setContentsMargins(0, 0, 0, 0)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.show()
self.update_info_button_text() # Initial setzen
# Windows Handle
self.hwnd = int(self.winId())
self.make_clickable(self.hwnd)
# Globaler Hotkey-Thread starten
threading.Thread(target=self.hotkey_listener, daemon=True).start()
# ---------------------------------------------
# �� Globale Hotkeys
# ---------------------------------------------
def hotkey_listener(self):
print("[Overlay] Hotkeys aktiv:")
print("F8 → Seite auf Deutsch übersetzen")
print("F9 → Beenden")
print("F10 → Klickdurchlässigkeit umschalten")
print("F11 → Transparenz erhöhen/verringern")
keyboard.add_hotkey("f8", self.translate_to_german)
keyboard.add_hotkey("f9", self.close_overlay)
keyboard.add_hotkey("f10", self.toggle_clickthrough)
keyboard.add_hotkey("f11", self.adjust_opacity)
keyboard.wait("f9")
# ---------------------------------------------
# �� Übersetzen (F8)
# ---------------------------------------------
def translate_to_german(self):
"""Lädt Google Translate Overlay."""
print("[Overlay] Übersetze Seite auf Deutsch ...")
js_code = """
if (!window.__googleTranslateLoaded) {
var gt = document.createElement('script');
gt.src = '//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit';
document.body.appendChild(gt);
window.googleTranslateElementInit = function() {
new google.translate.TranslateElement({pageLanguage: 'en', includedLanguages: 'de'}, 'google_translate_element');
};
var div = document.createElement('div');
div.id = 'google_translate_element';
div.style.position = 'fixed';
div.style.top = '10px';
div.style.right = '10px';
div.style.zIndex = '9999';
div.style.background = 'rgba(0,0,0,0.4)';
div.style.padding = '5px';
document.body.appendChild(div);
window.__googleTranslateLoaded = true;
}
"""
self.browser.page().runJavaScript(js_code)
# ---------------------------------------------
# �� Info-Button-Funktion
# ---------------------------------------------
def show_info_window(self):
"""Öffnet Info-Fenster für den aktuellen Dungeon."""
if not self.current_dungeon_name:
print("[Overlay] Kein Dungeon erkannt.")
return
def _norm(s: str) -> str:
return re.sub(r'[^a-z0-9]+', '', s.lower())
script_dir = os.path.dirname(os.path.abspath(__file__))
info_folder = os.path.join(script_dir, "Information")
if not os.path.isdir(info_folder):
print(f"[Overlay] Ordner 'Information' nicht gefunden: {info_folder}")
return
page_key = _norm(self.current_dungeon_name)
candidates = [f for f in os.listdir(info_folder) if f.lower().endswith(".html")]
norm_map = {_norm(os.path.splitext(f)[0]): f for f in candidates}
if page_key in norm_map:
file_name = norm_map[page_key]
file_path = os.path.join(info_folder, file_name)
print(f"[Overlay] Öffne Info-Datei: {file_path}")
info_window = QMainWindow(self)
info_window.setWindowTitle(f"Information - {file_name}")
info_window.setGeometry(self.geometry())
info_browser = QWebEngineView()
info_browser.setUrl(QUrl.fromLocalFile(file_path))
info_window.setCentralWidget(info_browser)
# --- Scrollt 660 Pixel runter nach dem Laden ---
def _scroll():
info_browser.page().runJavaScript("window.scrollTo(0, 880);")
print("[Overlay] Info-Seite 880px nach unten gescrollt.")
info_browser.loadFinished.connect(_scroll)
info_window.show()
else:
print("[Overlay] Keine passende Info-Datei gefunden.")
# ---------------------------------------------
# �� Info-Button-Text aktualisieren
# ---------------------------------------------
def update_info_button_text(self):
"""Setzt den Button-Text passend zur aktuellen URL."""
current_url = self.browser.url().toString()
parts = [p for p in current_url.rstrip("/").split("/") if p]
dungeon_name = parts[-1] if len(parts) > 0 else "unbekannt"
dungeon_display = dungeon_name.replace("-", " ").replace("_", " ").title()
self.current_dungeon_name = dungeon_name
self.info_button.setText(f"ℹ️nformationen über {dungeon_display}")
# ---------------------------------------------
# �� Klickdurchlässigkeit
# ---------------------------------------------
def make_clickthrough(self, hwnd):
GWL_EXSTYLE = -20
WS_EX_TRANSPARENT = 0x00000020
WS_EX_LAYERED = 0x00080000
style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, style | WS_EX_TRANSPARENT | WS_EX_LAYERED)
def make_clickable(self, hwnd):
GWL_EXSTYLE = -20
WS_EX_LAYERED = 0x00080000
style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, (style & ~0x00000020) | WS_EX_LAYERED)
def toggle_clickthrough(self):
self.click_through = not self.click_through
if self.click_through:
self.make_clickthrough(self.hwnd)
print("[Overlay] Klick-durchlässig aktiviert")
else:
self.make_clickable(self.hwnd)
print("[Overlay] Overlay ist jetzt interaktiv")
# ---------------------------------------------
# ��️ Transparenz
# ---------------------------------------------
def adjust_opacity(self):
if self.opacity > 0.5:
self.opacity -= 0.1
else:
self.opacity = 1
self.setWindowOpacity(self.opacity)
print(f"[Overlay] Transparenz: {self.opacity:.1f}")
# ---------------------------------------------
# �� Automatisches Scrollen
# ---------------------------------------------
def scroll_to_position(self):
js_code = f"window.scrollTo(0, {self.scroll_offset});"
self.browser.page().runJavaScript(js_code)
print(f"[Overlay] Seite wurde automatisch um {self.scroll_offset}px nach unten gescrollt.")
# ---------------------------------------------
# ❌ Beenden
# ---------------------------------------------
def close_overlay(self):
print("[Overlay] Beende Overlay...")
self.close()
sys.exit(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
url = "https://www.method.gg/fellowship/route-planner/"
overlay = GameOverlay(url)
sys.exit(app.exec_())


Hier die Erklärung warum:
Code:
Durch Verwendung von PyQt5.QtWebEngine – das ist im Prinzip ein kompletter eingebauter Chromium-Browser (~80–100 MB!). Diese Komponenten werden automatisch eingebunden: QtWebEngineCore.dll QtWebEngineWidgets.dll Qt5Gui.dll, Qt5Core.dll, Qt5Widgets.dll plus Chromium-Cache, Ressourcen & Plugin
Unten ist die py. Datei mit dem HTMLs zum runterladen.
Grüße






