facebook-tool/gui/handle/login_fb.py

175 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# gui/handle/login_fb.py
import os
import sys
import cv2
import numpy as np
from PyQt5.QtCore import Qt, QUrl, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel, QTextEdit, QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtGui import QImage, QPixmap
from services.action_service import ActionService
from services.detect_service import DetectService
from config import TEMPLATE_DIR
class LoginFB(QMainWindow):
def __init__(self, account=None, delay=0.1):
super().__init__()
self.account = account or {}
self.template_dir = os.path.abspath(TEMPLATE_DIR)
self.delay = delay
# --- Detect services ---
self.detector = DetectService(
template_dir=TEMPLATE_DIR,
target_labels=["username", "password", "buttons/login"]
)
# --- Detect login fail templates ---
self.fail_detector = DetectService(
template_dir=os.path.join(TEMPLATE_DIR, "login_fail")
)
# --- UI ---
self.setWindowTitle("FB Auto Vision Login")
self.setFixedSize(480, 680)
self.web = QWebEngineView()
self.web.setUrl(QUrl("https://facebook.com"))
self.web.setFixedSize(480, 480)
self.status = QLabel("Status: Ready")
self.status.setAlignment(Qt.AlignLeft)
self.status.setFixedHeight(20)
self.log_area = QTextEdit()
self.log_area.setReadOnly(True)
self.log_area.setFixedHeight(120)
self.log_area.setStyleSheet("""
background-color: #1e1e1e;
color: #dcdcdc;
font-size: 12px;
font-family: Consolas, monospace;
""")
self.btn_refresh = QPushButton("Refresh")
self.btn_refresh.setFixedHeight(30)
self.btn_refresh.clicked.connect(self.refresh_page)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.web)
layout.addWidget(self.status)
layout.addWidget(self.log_area)
layout.addWidget(self.btn_refresh)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.action = ActionService(webview=self.web, delay=self.delay)
self.login_clicked = False
# Giữ reference popup (nếu cần) hiện tại không dùng
# self.login_fail_popup = None
self.web.loadFinished.connect(self.on_web_loaded)
# ----------------------------------------------------
def log(self, message: str):
self.log_area.append(message)
print(message)
# ----------------------------------------------------
def capture_webview(self):
pixmap = self.web.grab()
if pixmap.isNull():
return None
qimg = pixmap.toImage().convertToFormat(QImage.Format_RGBA8888)
width, height = qimg.width(), qimg.height()
ptr = qimg.bits()
ptr.setsize(height * width * 4)
arr = np.frombuffer(ptr, np.uint8).reshape((height, width, 4))
return cv2.cvtColor(arr, cv2.COLOR_RGBA2BGR)
# ----------------------------------------------------
def on_web_loaded(self, ok=True):
"""Called every time page load finished"""
if not ok:
self.log("[ERROR] Page failed to load")
self.status.setText("Status: Page load failed")
return
screen = self.capture_webview()
if screen is None:
self.status.setText("Status: Unable to capture webview")
self.log("Status: Unable to capture webview")
return
# Nếu đang sau nhấn login, check login failure
if self.login_clicked:
self.log("[INFO] Page loaded after login click. Detecting login failure...")
fail_regions = self.fail_detector.detect(screen)
if fail_regions:
self.log(f"[FAIL] Login failed detected via template ({len(fail_regions)} regions):")
for folder_name, filename, top_left, bottom_right, score in fail_regions:
self.log(f" - {filename} @ {top_left}-{bottom_right} (score: {score:.2f})")
self.status.setText("Status: Login failed")
else:
self.log("[SUCCESS] Login seems successful!")
self.status.setText("Status: Login successful")
self.login_clicked = False
return
# Nếu là initial page load
self.log("[INFO] Page loaded. Starting template detection...")
regions = self.detector.detect(screen)
if not regions:
self.status.setText("[WARN] No regions detected")
self.log("[WARN] No regions detected")
return
self.status.setText(f"[INFO] Detected {len(regions)} valid regions")
self.log(f"[INFO] Detected {len(regions)} valid regions")
QTimer.singleShot(500, lambda: self.autofill_by_detection(regions))
# ----------------------------------------------------
def autofill_by_detection(self, regions):
email = self.account.get("email", "")
password = self.account.get("password", "")
for folder_name, filename, top_left, bottom_right, score in regions:
self.log(f"[ACTION] {folder_name}: {filename} ({score:.2f})")
label = folder_name.lower()
if ("user" in label or "email" in label) and email:
self.log(f"[DO] Filling email: {email}")
self.action.write_in_region(top_left, bottom_right, email)
elif "pass" in label and password:
self.log(f"[DO] Filling password: {'*' * len(password)}")
self.action.write_in_region(top_left, bottom_right, password)
elif "button" in label or "login" in label:
self.log("[DO] Clicking login button...")
self.login_clicked = True
self.action.click_center_of_region(top_left, bottom_right)
# ----------------------------------------------------
def refresh_page(self):
self.log("[INFO] Refreshing page...")
self.web.reload()
if __name__ == "__main__":
app = QApplication(sys.argv)
fake_account = {"email": "test@example.com", "password": "123456"}
win = LoginFB(account=fake_account)
win.show()
sys.exit(app.exec_())