facebook-tool/gui/handle/login_fb.py

174 lines
6.2 KiB
Python

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, QWebEngineProfile
from PyQt5.QtGui import QImage
from services.action_service import ActionService
from services.detect_service import DetectService
from services.profile_service import ProfileService
from config import TEMPLATE_DIR
class LoginFB(QMainWindow):
def __init__(self, account=None, delay=0.3):
super().__init__()
self.account = account or {}
self.template_dir = os.path.abspath(TEMPLATE_DIR)
self.delay = delay
# ✅ Lấy tên profile từ email hoặc username
self.profile_name = self.account.get("email") or self.account.get("username") or "default"
# --- Detect services ---
self.detector = DetectService(
template_dir=TEMPLATE_DIR,
target_labels=["username", "password"]
)
# --- UI cơ bản ---
self.setWindowTitle(f"FB Auto Vision Login - {self.profile_name}")
self.setFixedSize(480, 680)
self.web = QWebEngineView()
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)
# --- Profile ---
self.profile_service = ProfileService()
profile_path = self.profile_service.get_profile_path(self.profile_name)
profile = self.web.page().profile()
profile.setPersistentCookiesPolicy(QWebEngineProfile.ForcePersistentCookies)
profile.setPersistentStoragePath(profile_path)
self.log(f"[INFO] Profile applied at: {profile_path}")
# --- Webview ---
self.web.setUrl(QUrl("https://facebook.com"))
self.web.setFixedSize(480, 480)
# --- Layout ---
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)
# --- Services ---
self.action = ActionService(webview=self.web, delay=self.delay)
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):
if not ok:
self.log("[ERROR] Page failed to load")
self.status.setText("Status: Page load failed")
return
self.log("[INFO] Page loaded")
self.status.setText("Status: Page loaded")
# ✅ Lưu profile khi load xong
self.profile_service.save_profile(self.profile_name)
self.log(f"[INFO] Profile saved for {self.profile_name}")
# 🧠 Detect field
screen = self.capture_webview()
if screen is None:
self.status.setText("Status: Unable to capture webview")
self.log("Status: Unable to capture webview")
return
self.log("[INFO] Detecting email/password fields...")
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", "")
# sắp xếp để điền username trước, password sau
ordered = sorted(regions, key=lambda r: ("pass" in r[0].lower(), "user" not in r[0].lower()))
def do_action(i=0):
if i >= len(ordered):
return
folder_name, filename, top_left, bottom_right, score = ordered[i]
label = folder_name.lower()
self.log(f"[ACTION] {folder_name}: {filename} ({score:.2f})")
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)
QTimer.singleShot(int(self.delay * 1000), lambda: do_action(i + 1))
do_action()
# ----------------------------------------------------
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, delay=0.5)
win.show()
sys.exit(app.exec_())