feat: complete T-105b account login reuse
This commit is contained in:
+87
-2
@@ -7,7 +7,7 @@ from datetime import datetime
|
||||
from typing import Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from . import appconfig, chrome, db, editor
|
||||
from . import appconfig, cdp, chrome, db, editor
|
||||
from . import config as account_config
|
||||
|
||||
|
||||
@@ -42,6 +42,12 @@ def _required_text(value, field_name: str) -> str:
|
||||
return text
|
||||
|
||||
|
||||
def _account_value(account, field, default=None):
|
||||
if isinstance(account, dict):
|
||||
return account.get(field, default)
|
||||
return getattr(account, field, default)
|
||||
|
||||
|
||||
def normalize_region_host(value=None) -> str:
|
||||
text = _trim(value) or DEFAULT_REGION_HOST
|
||||
if "://" in text:
|
||||
@@ -208,9 +214,88 @@ def resolve_account(account_or_alias, path=None, config=None):
|
||||
return account_or_alias
|
||||
|
||||
|
||||
def _debug_host(account) -> str:
|
||||
return f"{chrome.CDP_HOST}:{normalize_debug_port(_account_value(account, 'debug_port'))}"
|
||||
|
||||
|
||||
def _seller_portal_url(account) -> str:
|
||||
return f"https://{normalize_region_host(_account_value(account, 'region_host'))}/portal/"
|
||||
|
||||
|
||||
def _find_login_tab(account, host):
|
||||
region_host = normalize_region_host(_account_value(account, 'region_host')).lower()
|
||||
seller_tabs = []
|
||||
login_tabs = []
|
||||
for tab in cdp.http_get("/json", host=host):
|
||||
if tab.get("type") != "page":
|
||||
continue
|
||||
url = str(tab.get("url") or "")
|
||||
lower_url = url.lower()
|
||||
if region_host in lower_url:
|
||||
seller_tabs.append(tab)
|
||||
elif "accounts.shopee." in lower_url and "/seller/login" in lower_url:
|
||||
login_tabs.append(tab)
|
||||
return (seller_tabs or login_tabs or [None])[0]
|
||||
|
||||
|
||||
def _open_or_activate_login_tab(account):
|
||||
host = _debug_host(account)
|
||||
portal_url = _seller_portal_url(account)
|
||||
tab = _find_login_tab(account, host)
|
||||
if tab:
|
||||
target_id = tab.get("id")
|
||||
if target_id:
|
||||
cdp.activate_tab(target_id, host=host)
|
||||
return {
|
||||
"target_id": target_id,
|
||||
"url": tab.get("url") or portal_url,
|
||||
"created_tab": False,
|
||||
}
|
||||
|
||||
tab = cdp.create_tab_info(portal_url, host=host)
|
||||
target_id = tab.get("id")
|
||||
if target_id:
|
||||
cdp.activate_tab(target_id, host=host)
|
||||
return {
|
||||
"target_id": target_id,
|
||||
"url": tab.get("url") or portal_url,
|
||||
"created_tab": True,
|
||||
}
|
||||
|
||||
|
||||
def launch_for_login(account_or_alias, path=None, config=None):
|
||||
account = resolve_account(account_or_alias, path=path, config=config)
|
||||
return chrome.launch_chrome(account, config=config)
|
||||
port = normalize_debug_port(_account_value(account, "debug_port"))
|
||||
alias = _account_value(account, "alias")
|
||||
|
||||
if chrome.is_running(port):
|
||||
tab = _open_or_activate_login_tab(account)
|
||||
return {
|
||||
"ok": True,
|
||||
"action": "reused",
|
||||
"reused": True,
|
||||
"launched": False,
|
||||
"alias": alias,
|
||||
"debug_port": port,
|
||||
"pid": None,
|
||||
**tab,
|
||||
}
|
||||
|
||||
process = chrome.launch_chrome(account, config=config)
|
||||
timeout = appconfig.cdp_ready_timeout(config)
|
||||
if not chrome.wait_debug_ready(port, timeout=timeout):
|
||||
raise AccountError(f"Chrome 已启动,但 CDP 端口 {port} 未在 {timeout} 秒内就绪")
|
||||
tab = _open_or_activate_login_tab(account)
|
||||
return {
|
||||
"ok": True,
|
||||
"action": "launched",
|
||||
"reused": False,
|
||||
"launched": True,
|
||||
"alias": alias,
|
||||
"debug_port": port,
|
||||
"pid": getattr(process, "pid", None),
|
||||
**tab,
|
||||
}
|
||||
|
||||
|
||||
def create_shortcut(account_or_alias, shortcut_path=None, desktop_dir=None, path=None, config=None) -> str:
|
||||
|
||||
+14
@@ -43,6 +43,20 @@ def close_tab(target_id, host=None):
|
||||
return response.ok
|
||||
|
||||
|
||||
def activate_tab(target_id, host=None):
|
||||
"""Bring an existing Chrome target/page to the foreground."""
|
||||
|
||||
if not target_id:
|
||||
return False
|
||||
ver = http_get("/json/version", host=host)
|
||||
b = CDP(ver["webSocketDebuggerUrl"])
|
||||
try:
|
||||
b.send("Target.activateTarget", {"targetId": target_id})
|
||||
finally:
|
||||
b.close()
|
||||
return True
|
||||
|
||||
|
||||
class CDP:
|
||||
"""单个 target 的 CDP 客户端:命令同步、事件回调异步。"""
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ class AccountsTab(QWidget):
|
||||
account=account,
|
||||
)
|
||||
try:
|
||||
process = accounts.launch_for_login(account, config=self.config)
|
||||
launch_result = accounts.launch_for_login(account, config=self.config)
|
||||
except Exception as exc:
|
||||
elapsed_ms = _elapsed_ms(started)
|
||||
safe_error = diagnostics.redact_log_text(str(exc) or exc.__class__.__name__)
|
||||
@@ -344,10 +344,17 @@ class AccountsTab(QWidget):
|
||||
self._show_error(safe_error)
|
||||
return
|
||||
elapsed_ms = _elapsed_ms(started)
|
||||
pid = getattr(process, "pid", None)
|
||||
action = (launch_result or {}).get("action") or "launched"
|
||||
pid = (launch_result or {}).get("pid")
|
||||
target_id = (launch_result or {}).get("target_id") or ""
|
||||
url = (launch_result or {}).get("url") or ""
|
||||
event_result = "reused" if action == "reused" else "launched"
|
||||
_safe_add_run_log_event(
|
||||
run_id,
|
||||
f"step=launch_chrome result=success detail=账号 {account.alias} pid={pid or ''} elapsed_ms={elapsed_ms}",
|
||||
(
|
||||
f"step=launch_chrome result={event_result} detail=账号 {account.alias} "
|
||||
f"pid={pid or ''} target_id={target_id} url={url} elapsed_ms={elapsed_ms}"
|
||||
),
|
||||
db_path=self.db_path,
|
||||
account=account,
|
||||
)
|
||||
@@ -358,11 +365,22 @@ class AccountsTab(QWidget):
|
||||
done=1,
|
||||
success_count=1,
|
||||
failed_count=0,
|
||||
summary_json={"ok": True, "alias": account.alias, "debug_port": account.debug_port, "pid": pid},
|
||||
summary_json={
|
||||
"ok": True,
|
||||
"alias": account.alias,
|
||||
"debug_port": account.debug_port,
|
||||
"action": action,
|
||||
"pid": pid,
|
||||
"target_id": target_id,
|
||||
"url": url,
|
||||
},
|
||||
)
|
||||
self.login_statuses[account.alias] = "已启动"
|
||||
self.refresh_accounts()
|
||||
self._set_status("Chrome 已启动,请人工登录")
|
||||
if action == "reused":
|
||||
self._set_status("该账号 Chrome 已打开,已复用现有窗口")
|
||||
else:
|
||||
self._set_status("Chrome 已启动,请人工登录")
|
||||
|
||||
def check_login(self, checked=False):
|
||||
account = self._selected_account()
|
||||
|
||||
Reference in New Issue
Block a user