"""Chrome/Edge 独立 Profile:启用「继续上次会话」,让 Session Cookie 可跨次打开保留。""" from __future__ import annotations import json import logging import os from typing import Any, Dict logger = logging.getLogger(__name__) RESTORE_CONTINUE_WHERE_LEFT_OFF = 1 def preferences_path(profile_dir: str) -> str: return os.path.join(os.path.abspath(profile_dir), "Default", "Preferences") def ensure_session_restore(profile_dir: str) -> Dict[str, Any]: """启动浏览器前写入 session.restore_on_startup=1;Crashed → Normal。""" profile_abs = os.path.abspath(profile_dir) prefs = preferences_path(profile_abs) os.makedirs(os.path.dirname(prefs), exist_ok=True) data: Dict[str, Any] = {} existed = os.path.isfile(prefs) if existed: try: with open(prefs, "r", encoding="utf-8") as fh: data = json.load(fh) except Exception: logger.exception("chrome_prefs_read_failed path=%s", prefs) data = {} before = int((data.get("session") or {}).get("restore_on_startup") or 0) exit_before = str((data.get("profile") or {}).get("exit_type") or "") session = data.setdefault("session", {}) session["restore_on_startup"] = RESTORE_CONTINUE_WHERE_LEFT_OFF profile = data.setdefault("profile", {}) if str(profile.get("exit_type") or "").lower() == "crashed": profile["exit_type"] = "Normal" try: with open(prefs, "w", encoding="utf-8") as fh: json.dump(data, fh, ensure_ascii=False, separators=(",", ":")) except Exception as exc: logger.warning("chrome_prefs_write_failed path=%s err=%s", prefs, exc) return { "ok": False, "path": prefs, "existed": existed, "restore_before": before, "restore_after": before, "exit_type_before": exit_before, "error": str(exc), } after = int((data.get("session") or {}).get("restore_on_startup") or 0) exit_after = str((data.get("profile") or {}).get("exit_type") or "") logger.info( "chrome_session_restore_ensured profile_dir=%s prefs=%s existed=%s " "restore_on_startup %s->%s exit_type %s->%s", profile_abs, prefs, existed, before, after, exit_before or "-", exit_after or "-", ) return { "ok": True, "path": prefs, "existed": existed, "restore_before": before, "restore_after": after, "exit_type_before": exit_before, "exit_type_after": exit_after, }