facebook-tool/services/profile_service.py

151 lines
5.8 KiB
Python

# services/profile_service.py
import os
import re
import shutil
import logging
from typing import Optional, List
from config import PROFILES_DIR # 👈 dùng từ config
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
def _sanitize_name(name: str) -> str:
"""
Chuyển tên (email/username) thành dạng an toàn cho filesystem.
Giữ chữ, số, dấu gạch ngang và gạch dưới.
Ví dụ: "user+test@example.com" -> "user-test_example-com"
"""
if not isinstance(name, str):
raise ValueError("Profile name must be a string")
name = name.strip().lower()
# Thay các kí tự '@' và '+' thành '-'
name = name.replace("@", "-at-").replace("+", "-plus-")
# Thay các kí tự không an toàn thành '-'
name = re.sub(r"[^a-z0-9._-]", "-", name)
# Compact nhiều dấu '-' liên tiếp
name = re.sub(r"-{2,}", "-", name)
# Trim dấu '-' đầu cuối
name = name.strip("-")
return name or "profile"
class ProfileService:
"""
Service để quản lý thư mục profiles.
Mặc định root folder lấy từ config.PROFILES_DIR.
"""
base_dir = PROFILES_DIR
def __init__(self, profiles_root: Optional[str] = None):
# 👇 Dùng PROFILES_DIR nếu không truyền thủ công
self.profiles_root = os.path.abspath(profiles_root or PROFILES_DIR)
os.makedirs(self.profiles_root, exist_ok=True)
logger.info("Profiles root: %s", self.profiles_root)
def get_profile_dirname(self, name: str) -> str:
"""Tên folder đã sanitize (chỉ tên folder, không có path)"""
return _sanitize_name(name)
def save_profile(self, key: str):
# ở đây có thể không cần làm gì nhiều vì Qt tự lưu cookie
# nhưng bạn có thể log hoặc thêm custom logic
print(f"[ProfileService] Saved profile for {key}")
def get_profile_path(self, key: str) -> str:
path = os.path.join(self.base_dir, key)
os.makedirs(path, exist_ok=True)
return path
def exists(self, name: str) -> bool:
"""Check folder có tồn tại không"""
return os.path.isdir(self.get_profile_path(name))
def create(self, name: str, copy_from: Optional[str] = None, exist_ok: bool = True) -> str:
"""
Tạo folder profile.
- name: email/username
- copy_from: nếu truyền path tới folder mẫu, sẽ copy nội dung từ đó
- exist_ok: nếu True và folder đã tồn tại thì không raise
Trả về path tới folder profile.
"""
path = self.get_profile_path(name)
if os.path.isdir(path):
if exist_ok:
logger.debug("Profile already exists: %s", path)
return path
raise FileExistsError(f"Profile already exists: {path}")
os.makedirs(path, exist_ok=True)
logger.info("Created profile dir: %s", path)
if copy_from:
copy_from = os.path.abspath(copy_from)
if os.path.isdir(copy_from):
for item in os.listdir(copy_from):
s = os.path.join(copy_from, item)
d = os.path.join(path, item)
if os.path.isdir(s):
shutil.copytree(s, d, dirs_exist_ok=True)
else:
shutil.copy2(s, d)
logger.info("Copied profile template from %s to %s", copy_from, path)
else:
logger.warning("copy_from path not found or not a dir: %s", copy_from)
return path
def delete(self, name: str, ignore_errors: bool = False) -> None:
"""Xóa folder profile (recursive)."""
path = self.get_profile_path(name)
if not os.path.isdir(path):
raise FileNotFoundError(f"Profile not found: {path}")
shutil.rmtree(path, ignore_errors=ignore_errors)
logger.info("Deleted profile dir: %s", path)
def list_profiles(self) -> List[str]:
"""Trả về danh sách tên folder (dirnames) trong profiles_root."""
try:
return sorted(
[
d
for d in os.listdir(self.profiles_root)
if os.path.isdir(os.path.join(self.profiles_root, d))
]
)
except FileNotFoundError:
return []
# ----------------- Optional: QWebEngineProfile creator -----------------
def create_qwebengine_profile(self, name: str, parent=None, profile_id: Optional[str] = None):
"""
Tạo và trả về QWebEngineProfile đã cấu hình persistent storage (cookies, local storage, cache).
Yêu cầu PyQt5.QtWebEngineWidgets được cài.
- name: email/username để đặt thư mục lưu
- parent: parent QObject cho QWebEngineProfile (thường là self)
- profile_id: tên id cho profile (tùy chọn)
"""
try:
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
except Exception as e:
raise RuntimeError(
"PyQt5.QtWebEngineWidgets không khả dụng. "
"Không thể tạo QWebEngineProfile."
) from e
profile_path = self.get_profile_path(name)
os.makedirs(profile_path, exist_ok=True)
profile_name = profile_id or self.get_profile_dirname(name)
profile = QWebEngineProfile(profile_name, parent)
profile.setPersistentStoragePath(profile_path)
profile.setCachePath(profile_path)
# Force lưu cookie persist
try:
profile.setPersistentCookiesPolicy(QWebEngineProfile.ForcePersistentCookies)
except Exception:
pass
logger.info("Created QWebEngineProfile for %s -> %s", name, profile_path)
return profile