added very basic web replayer
This commit is contained in:
parent
30dd5410f0
commit
12617346d7
4 changed files with 162 additions and 0 deletions
21
tools/web_replay/main.py
Normal file
21
tools/web_replay/main.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
|
from tools.web_replay.ui import ReplayWindow
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# create the application
|
||||||
|
application = QApplication(sys.argv)
|
||||||
|
|
||||||
|
from source.utils import compress
|
||||||
|
with open(r"C:\Users\RC606\Downloads\41a6268b-72e5-47a9-8106-6c15a0be366e.rsl", "rb") as file:
|
||||||
|
data = compress.uncompress_data(file.read())
|
||||||
|
|
||||||
|
# create the window
|
||||||
|
window = ReplayWindow(data["surveys"]["mission-gift-card"]["event"])
|
||||||
|
window.show()
|
||||||
|
|
||||||
|
# start the application
|
||||||
|
application.exec()
|
121
tools/web_replay/ui/ReplayEngine.py
Normal file
121
tools/web_replay/ui/ReplayEngine.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
from PyQt6.QtCore import Qt, QUrl, QSize, QPointF
|
||||||
|
from PyQt6.QtGui import QKeyEvent, QMouseEvent
|
||||||
|
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||||
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QApplication
|
||||||
|
|
||||||
|
|
||||||
|
class ReplayEngine(QWidget):
|
||||||
|
"""
|
||||||
|
This widget allow to replay some event that occurred on a web page
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, replay_data: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.replay_data = replay_data
|
||||||
|
self.iterator = iter(self.replay_data)
|
||||||
|
|
||||||
|
# layout
|
||||||
|
self._layout = QVBoxLayout()
|
||||||
|
self.setLayout(self._layout)
|
||||||
|
|
||||||
|
# cursor
|
||||||
|
self.cursor = QLabel(self)
|
||||||
|
self.cursor.setFixedSize(20, 20)
|
||||||
|
self.cursor.setStyleSheet("background-color: red; border-radius: 10px;")
|
||||||
|
|
||||||
|
# web
|
||||||
|
self.web = QWebEngineView()
|
||||||
|
self._layout.addWidget(self.web)
|
||||||
|
|
||||||
|
def run_event(self, event: dict):
|
||||||
|
match event["type"]:
|
||||||
|
case "success":
|
||||||
|
# success event
|
||||||
|
print(f"success ! ({event['time']}s)")
|
||||||
|
|
||||||
|
case "url":
|
||||||
|
# changing url event
|
||||||
|
self.web.setUrl(QUrl(event["url"]))
|
||||||
|
|
||||||
|
case "resize":
|
||||||
|
# changing widget size event
|
||||||
|
self.web.resize(QSize(*event["size"]))
|
||||||
|
|
||||||
|
# TODO: better way ?
|
||||||
|
self.window().resize(QSize(*event["size"]))
|
||||||
|
|
||||||
|
case "keyboard_press":
|
||||||
|
# keyboard key pressed event
|
||||||
|
key = QKeyEvent(
|
||||||
|
QKeyEvent.Type.KeyPress,
|
||||||
|
event["key"],
|
||||||
|
Qt.KeyboardModifier.NoModifier
|
||||||
|
)
|
||||||
|
QApplication.sendEvent(self.web.page(), key)
|
||||||
|
|
||||||
|
case "keyboard_release":
|
||||||
|
# keyboard key released event
|
||||||
|
key = QKeyEvent(
|
||||||
|
QKeyEvent.Type.KeyRelease,
|
||||||
|
event["key"],
|
||||||
|
Qt.KeyboardModifier.NoModifier
|
||||||
|
)
|
||||||
|
QApplication.sendEvent(self.web.page(), key)
|
||||||
|
|
||||||
|
case "mouse_press":
|
||||||
|
# mouse pressed event
|
||||||
|
key = QMouseEvent(
|
||||||
|
QMouseEvent.Type.KeyPress,
|
||||||
|
QPointF(*event["position"]),
|
||||||
|
Qt.MouseButton(event["button"]),
|
||||||
|
Qt.MouseButton.NoButton,
|
||||||
|
Qt.KeyboardModifier.NoModifier
|
||||||
|
)
|
||||||
|
QApplication.sendEvent(self.web.page(), key)
|
||||||
|
|
||||||
|
case "mouse_release":
|
||||||
|
# mouse pressed event
|
||||||
|
key = QMouseEvent(
|
||||||
|
QMouseEvent.Type.KeyRelease,
|
||||||
|
QPointF(*event["position"]),
|
||||||
|
Qt.MouseButton(event["button"]),
|
||||||
|
Qt.MouseButton.NoButton,
|
||||||
|
Qt.KeyboardModifier.NoModifier
|
||||||
|
)
|
||||||
|
QApplication.sendEvent(self.web.page(), key)
|
||||||
|
|
||||||
|
# NOTE: this event is redundant
|
||||||
|
# case "mouse_double_click":
|
||||||
|
# # mouse double-clicked event
|
||||||
|
# key = QMouseEvent(QMouseEvent.Type.MouseButtonDblClick, event["position"], event["button"])
|
||||||
|
# QApplication.sendEvent(self.page(), key)
|
||||||
|
|
||||||
|
case "mouse_move":
|
||||||
|
# mouse moved event
|
||||||
|
key = QMouseEvent(
|
||||||
|
QMouseEvent.Type.KeyRelease,
|
||||||
|
QPointF(*event["position"]),
|
||||||
|
Qt.MouseButton.NoButton,
|
||||||
|
Qt.MouseButton.NoButton,
|
||||||
|
Qt.KeyboardModifier.NoModifier
|
||||||
|
)
|
||||||
|
QApplication.sendEvent(self.web.page(), key)
|
||||||
|
|
||||||
|
# move the fake cursor
|
||||||
|
self.cursor.move(QPointF(*event["position"]).toPoint() - self.cursor.rect().center())
|
||||||
|
self.cursor.raise_()
|
||||||
|
|
||||||
|
case "scroll":
|
||||||
|
# scroll event
|
||||||
|
x, y = event["position"]
|
||||||
|
self.web.page().runJavaScript(f"window.scrollTo({x}, {y});")
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
try:
|
||||||
|
event = next(self.iterator)
|
||||||
|
except StopIteration:
|
||||||
|
print("end of record")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.run_event(event)
|
18
tools/web_replay/ui/ReplayWindow.py
Normal file
18
tools/web_replay/ui/ReplayWindow.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from PyQt6.QtCore import QTimer
|
||||||
|
from PyQt6.QtWidgets import QMainWindow
|
||||||
|
|
||||||
|
from tools.web_replay.ui import ReplayEngine
|
||||||
|
|
||||||
|
|
||||||
|
class ReplayWindow(QMainWindow):
|
||||||
|
def __init__(self, replay_data: dict):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.replay_engine = ReplayEngine(replay_data)
|
||||||
|
self.setCentralWidget(self.replay_engine)
|
||||||
|
|
||||||
|
# TODO: TEST REMOVE
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.setInterval(10)
|
||||||
|
self.timer.timeout.connect(self.replay_engine.next) # NOQA: connect exist
|
||||||
|
self.timer.start()
|
2
tools/web_replay/ui/__init__.py
Normal file
2
tools/web_replay/ui/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
from .ReplayEngine import ReplayEngine
|
||||||
|
from .ReplayWindow import ReplayWindow
|
Loading…
Reference in a new issue