Files
live-hub-py/gui/state.py
T
2026-06-22 10:10:51 +08:00

116 lines
3.6 KiB
Python

"""GUI本地状态存储。"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from loguru import logger
from douyu.config import Account, ProxyConfig
from douyu.email_verifier import get_email_config_for_account
DEFAULT_STATE_PATH = Path("data/gui_state.json")
def account_to_dict(account: Account) -> dict[str, Any]:
"""把账号对象转换成可保存的字典。"""
return {
"username": account.username,
"password": account.password,
"email": account.email,
"email_password": account.email_password,
"email_imap_server": account.email_imap_server,
"email_imap_port": account.email_imap_port,
}
def account_from_dict(data: dict[str, Any]) -> Account | None:
"""从本地状态恢复账号对象。"""
username = str(data.get("username", "")).strip()
password = str(data.get("password", "")).strip()
email = str(data.get("email", "")).strip()
email_password = str(data.get("email_password", "")).strip()
if not all([username, password, email, email_password]):
return None
email_config = get_email_config_for_account(email)
imap_server = str(data.get("email_imap_server") or email_config["server"]).strip()
try:
imap_port = int(data.get("email_imap_port") or email_config["port"])
except (TypeError, ValueError):
imap_port = int(email_config["port"])
return Account(
username=username,
password=password,
email=email,
email_password=email_password,
email_imap_server=imap_server,
email_imap_port=imap_port,
)
class GuiStateStore:
"""负责保存和读取GUI状态。"""
def __init__(self, path: str | Path = DEFAULT_STATE_PATH):
self.path = Path(path)
def load(self) -> dict[str, Any]:
"""读取本地状态文件。"""
if not self.path.exists():
return {}
try:
with self.path.open("r", encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, dict) else {}
except Exception as exc:
logger.warning(f"读取GUI状态失败,将使用默认值: {exc}")
return {}
def save(self, state: dict[str, Any]) -> None:
"""原子写入本地状态文件。"""
self.path.parent.mkdir(parents=True, exist_ok=True)
tmp_path = self.path.with_suffix(f"{self.path.suffix}.tmp")
with tmp_path.open("w", encoding="utf-8") as f:
json.dump(state, f, ensure_ascii=False, indent=2)
tmp_path.replace(self.path)
@staticmethod
def accounts_from_state(state: dict[str, Any]) -> list[Account]:
"""从状态字典恢复账号列表。"""
accounts = []
raw_accounts = state.get("accounts", [])
if not isinstance(raw_accounts, list):
return accounts
for raw_account in raw_accounts:
if not isinstance(raw_account, dict):
continue
account = account_from_dict(raw_account)
if account:
accounts.append(account)
return accounts
@staticmethod
def proxy_from_state(state: dict[str, Any]) -> ProxyConfig:
"""从状态字典恢复代理配置。"""
proxy = state.get("proxy", {})
if not isinstance(proxy, dict):
return ProxyConfig()
return ProxyConfig(
enabled=bool(proxy.get("enabled", False)),
api_url=str(proxy.get("api_url", "")).strip(),
http=str(proxy.get("http", "")).strip(),
https=str(proxy.get("https", "")).strip(),
)