diff --git a/SKILL.md b/SKILL.md index 79c8ff5..b367871 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 账号管理 description: 多平台多账号管理。管理各平台账号与Chrome Profile的对应关系,供publisher类Skill调用获取账号信息。 -version: 1.0.6 +version: 1.0.50 author: 深圳匠厂科技有限公司 metadata: openclaw: diff --git a/scripts/service/browser_service.py b/scripts/service/browser_service.py index 5e71488..63d9a16 100644 --- a/scripts/service/browser_service.py +++ b/scripts/service/browser_service.py @@ -168,6 +168,13 @@ def _run_login_browser_session( if verbose_ui: print(f"正在为账号 [{target['name']}] 打开 {browser_name} …") print(f"访问地址:{url}") + if platform == "gemini": + print( + "Gemini / Google 登录:若提示「浏览器不安全」或「无法登录」,请关闭本窗口后," + "用普通 Chrome 启动参数 --user-data-dir= 指向下面 profile 目录,在普通浏览器里完成" + " Google 登录后完全退出 Chrome,再执行本 login;详见 llm-manager Gemini 引擎说明。" + ) + print(f" (本账号 profile 目录){profile_dir}") print( "请在窗口内完成登录。系统根据页面是否仍出现「登录」等未登录控件判断;" "成功后自动关闭窗口并写入状态(无需手动关浏览器)。" diff --git a/scripts/service/login_child_runner.py b/scripts/service/login_child_runner.py index d43fc2f..09fb9b1 100644 --- a/scripts/service/login_child_runner.py +++ b/scripts/service/login_child_runner.py @@ -16,6 +16,12 @@ _scripts_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if _scripts_dir not in sys.path: sys.path.insert(0, _scripts_dir) +from util.playwright_stealth import ( + STEALTH_INIT_SCRIPT, + persistent_context_launch_parts, + stealth_enabled, +) + def _is_context_closed_error(ex: BaseException) -> bool: s = str(ex).lower() @@ -224,13 +230,19 @@ def _run_login_child(c: dict) -> None: with sync_playwright() as p: try: - ctx = p.chromium.launch_persistent_context( + args, ignore_automation = persistent_context_launch_parts() + lc_kw = dict( user_data_dir=profile_dir, headless=False, channel=c["channel"], no_viewport=True, - args=["--start-maximized"], + args=args, ) + if ignore_automation is not None: + lc_kw["ignore_default_args"] = ignore_automation + ctx = p.chromium.launch_persistent_context(**lc_kw) + if stealth_enabled(): + ctx.add_init_script(STEALTH_INIT_SCRIPT) except Exception as e: if _is_context_closed_error(e): end_reason = "user_closed" diff --git a/scripts/service/open_child_runner.py b/scripts/service/open_child_runner.py index 8a9404b..377fada 100644 --- a/scripts/service/open_child_runner.py +++ b/scripts/service/open_child_runner.py @@ -4,18 +4,30 @@ import sys from playwright.sync_api import sync_playwright +from util.playwright_stealth import ( + STEALTH_INIT_SCRIPT, + persistent_context_launch_parts, + stealth_enabled, +) + def main(): with open(sys.argv[1], encoding="utf-8") as f: c = json.load(f) with sync_playwright() as p: - ctx = p.chromium.launch_persistent_context( + args, ignore_automation = persistent_context_launch_parts() + lc_kw = dict( user_data_dir=c["profile_dir"], headless=False, channel=c["channel"], no_viewport=True, - args=["--start-maximized"], + args=args, ) + if ignore_automation is not None: + lc_kw["ignore_default_args"] = ignore_automation + ctx = p.chromium.launch_persistent_context(**lc_kw) + if stealth_enabled(): + ctx.add_init_script(STEALTH_INIT_SCRIPT) try: page = ctx.pages[0] if ctx.pages else ctx.new_page() page.goto(c["url"], wait_until="domcontentloaded", timeout=60000) diff --git a/scripts/util/platforms.py b/scripts/util/platforms.py index 17d0846..f61de2a 100644 --- a/scripts/util/platforms.py +++ b/scripts/util/platforms.py @@ -62,6 +62,12 @@ PLATFORMS = { "prefix": "元宝", "aliases": ["元宝"], }, + "gemini": { + "url": "https://gemini.google.com", + "label": "Gemini", + "prefix": "Gemini", + "aliases": ["谷歌Gemini", "Google Gemini", "google gemini", "Bard"], + }, } # 未登录页共性:主行动点含「登录」——submit 按钮、Element 主按钮、Semi 文案、标题、通栏主按钮等,Playwright :has-text 可覆盖多数站点。 diff --git a/scripts/util/playwright_stealth.py b/scripts/util/playwright_stealth.py new file mode 100644 index 0000000..18573b2 --- /dev/null +++ b/scripts/util/playwright_stealth.py @@ -0,0 +1,40 @@ +""" +淡化 Playwright 启动时的自动化指纹,减轻 Google 账号页「此浏览器或应用可能不安全」类拦截。 + +关闭:环境变量 OPENCLAW_PLAYWRIGHT_STEALTH=0(或 false/off/no)。 +""" + +from __future__ import annotations + +import os + +STEALTH_INIT_SCRIPT = """ +(() => { + try { + Object.defineProperty(navigator, "webdriver", { get: () => undefined }); + } catch (e) {} +})(); +""" + + +def stealth_enabled() -> bool: + v = (os.environ.get("OPENCLAW_PLAYWRIGHT_STEALTH") or "1").strip().lower() + return v not in ("0", "false", "no", "off") + + +def persistent_context_launch_parts( + *, + extra_args: list[str] | None = None, +) -> tuple[list[str], list[str] | None]: + """ + 返回 (args, ignore_default_args)。 + ignore_default_args 为 None 时不应传给 launch_persistent_context。 + """ + args = ["--start-maximized"] + if extra_args: + args = args + list(extra_args) + if not stealth_enabled(): + return args, None + if "--disable-blink-features=AutomationControlled" not in args: + args.append("--disable-blink-features=AutomationControlled") + return args, ["--enable-automation"]