v0.4: background reads, JS-state login signals, blind sleeps dropped

get_or_open_tab(activate=True) — added, not replaced. Read paths pass
activate=False; post flows keep the foreground for dialogs and file inputs.

check_login moved off DOM signals onto session state: fb c_user, ig/threads
ds_user_id, twitter twid, yt ytcfg.LOGGED_IN. Three platforms were reporting
OUT on a signed-in account because their composer never mounts in a hidden
tab. The fixed sleep(4)/sleep(5) before each check goes with them — every
signal reads present the moment navigate() returns.

Unreadable cookies raise instead of returning False: "cannot tell" is not
"signed out". tiktok untouched and still activated — it reported
visibilityState "visible" from a sibling-activated tab, so it has never been
read from a genuine background.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-13 01:58:25 +08:00
co-authored by Claude Opus 5
parent 1ac06c1bbe
commit 5419b08264
7 changed files with 85 additions and 30 deletions
+12 -5
View File
@@ -80,15 +80,22 @@ async def _flow(tab, text, media_path, visibility):
async def check_login(cdp_client):
tab, reused = await cdp_client.get_or_open_tab(S["url"], "facebook.com")
tab, reused = await cdp_client.get_or_open_tab(S["url"], "facebook.com", activate=False)
if reused:
# Dismiss any leftover dialog (e.g. unsaved Create Post from a failed run)
await tab.eval("window.onbeforeunload = null")
await tab.navigate(S["url"])
await asyncio.sleep(4)
if await tab.exists(S["login_marker"]):
return False
return await tab.eval(
"(() => !![...document.querySelectorAll('span')].find(s => s.innerText"
" && s.innerText.toLowerCase().includes('on your mind')))()"
# JS state, not the composer's "on your mind" span: that string is
# localised, A/B'd, and absent until the feed renders, so a signed-in
# account reads as signed out. The c_user cookie is the session itself.
state = await tab.eval(
"(() => { const m = document.cookie.match(/(?:^|;\\s*)c_user=(\\d+)/);"
" return m ? 'in:' + m[1] : (document.cookie ? 'out' : 'unavailable'); })()"
)
if state.startswith("in:"):
return True
if state == "out":
return False
raise CDPError("fb: no cookies readable on facebook.com — cannot tell signed-in from signed-out")