# -*- coding: utf-8 -*- """ Chromium/Edge browser profile opener. Uses system Chrome/Edge channel, Playwright launch_persistent_context. Does NOT download Playwright Chromium. Does NOT check login status. Does NOT write secret to SQLite. """ import json import os import subprocess import sys import tempfile from db.connection import init_db from db.accounts_repo import get_account_by_id from util.logging_config import ( get_skill_logger, subprocess_env_with_trace, ) from util.platforms import PLATFORMS # 子进程入口脚本与本模块同目录(独立解释器执行,非 import) _SERVICE_DIR = os.path.dirname(os.path.abspath(__file__)) _SCRIPTS_ROOT = os.path.dirname(_SERVICE_DIR) def _win_find_exe(candidates): for p in candidates: if p and os.path.isfile(p): return p return None def resolve_chromium_channel(): """ Playwright channel: 'chrome' | 'msedge' | None Windows 优先 Chrome,其次 Edge;其它系统默认 chrome(由 Playwright 解析 PATH)。 """ if sys.platform != "win32": return "chrome" pf = os.environ.get("ProgramFiles", r"C:\Program Files") pfx86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)") local = os.environ.get("LocalAppData", "") chrome = _win_find_exe( [ os.path.join(pf, "Google", "Chrome", "Application", "chrome.exe"), os.path.join(pfx86, "Google", "Chrome", "Application", "chrome.exe"), os.path.join(local, "Google", "Chrome", "Application", "chrome.exe") if local else "", ] ) if chrome: return "chrome" edge = _win_find_exe( [ os.path.join(pfx86, "Microsoft", "Edge", "Application", "msedge.exe"), os.path.join(pf, "Microsoft", "Edge", "Application", "msedge.exe"), os.path.join(local, "Microsoft", "Edge", "Application", "msedge.exe") if local else "", ] ) if edge: return "msedge" return None def _print_browser_install_hint(): print("❌ 未检测到 Google Chrome 或 Microsoft Edge,请先安装:") print(" • Chrome: https://www.google.com/chrome/") print(" • Edge: https://www.microsoft.com/zh-cn/edge") def cmd_open(account_id): """ 打开该账号的持久化浏览器,仅用于肉眼核对。 不写数据库、不判定是否已登录。 """ log = get_skill_logger() init_db() log.info("browser_open_start account_id=%r", account_id) target = get_account_by_id(account_id) if not target: log.warning("browser_open_error account_id=%r not_found", account_id) print("ERROR:ACCOUNT_NOT_FOUND") return channel = resolve_chromium_channel() if not channel: _print_browser_install_hint() return try: import playwright # noqa: F401 except ImportError: print( "ERROR:需要 playwright Python 包。" ) return profile_dir = (target.get("profile_dir") or "").strip() if not profile_dir: log.warning("browser_open_error account_id=%s profile_dir_missing", account_id) print("ERROR:PROFILE_DIR_MISSING 账号中 profile_dir 为空。") return os.makedirs(profile_dir, exist_ok=True) # Use account url, fall back to platform default platform_spec = PLATFORMS.get(target["platform_key"], {}) url = (target.get("url") or "").strip() or platform_spec.get("default_url", "") log.info( "browser_open_context profile_dir=%s url=%s channel=%s platform=%s", profile_dir, url, channel, target.get("platform_key"), ) browser_name = "Google Chrome" if channel == "chrome" else "Microsoft Edge" print(f"正在打开 [{target['account_label']}] 的 {browser_name}(仅查看,不写入数据库)") print(f"地址:{url}") print("本命令不做登录检测。") cfg = {"channel": channel, "profile_dir": profile_dir, "url": url} with tempfile.NamedTemporaryFile( mode="w", suffix=".json", delete=False, encoding="utf-8" ) as jf: json.dump(cfg, jf, ensure_ascii=False) cfg_path = jf.name try: subprocess.run( [sys.executable, "-m", "service.open_child_runner", cfg_path], cwd=_SCRIPTS_ROOT, env=subprocess_env_with_trace(), ) log.info("browser_open_close account_id=%s channel=%s", account_id, channel) except Exception as e: log.error("browser_open_error account_id=%s error=%s", account_id, str(e)) raise finally: try: os.unlink(cfg_path) except OSError: pass