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:
@@ -22,6 +22,7 @@ import base64
|
||||
import json
|
||||
import random
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
import websockets
|
||||
@@ -50,9 +51,10 @@ def _http_get_json(url, timeout=5.0):
|
||||
with urllib.request.urlopen(url, timeout=timeout) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
except urllib.error.URLError as exc:
|
||||
port = urllib.parse.urlsplit(url).port
|
||||
raise CDPError(
|
||||
f"CDP endpoint unreachable at {url}: {exc}. "
|
||||
"Is Brave running with --remote-debugging-port=9222?"
|
||||
f"Is Brave running with --remote-debugging-port={port}?"
|
||||
) from exc
|
||||
except json.JSONDecodeError as exc:
|
||||
raise CDPError(f"CDP endpoint {url} returned non-JSON: {exc}") from exc
|
||||
@@ -174,16 +176,23 @@ class CDPClient:
|
||||
return await self._attach(info["targetId"])
|
||||
raise CDPError(f"no open tab whose URL contains {url_contains!r}")
|
||||
|
||||
async def get_or_open_tab(self, url, url_contains):
|
||||
async def get_or_open_tab(self, url, url_contains, activate=True):
|
||||
"""Reuse a warm existing tab if one matches, otherwise open a fresh one.
|
||||
Returns (tab, reused: bool). Caller should skip tab.close() when reused.
|
||||
|
||||
A reused tab is brought to the front — see Tab.activate() for why a
|
||||
backgrounded tab cannot be trusted to have rendered.
|
||||
A reused tab is brought to the front by default — see Tab.activate() for
|
||||
why a backgrounded tab cannot be trusted to have rendered.
|
||||
|
||||
`activate=False` is for callers that read a **JS-state** signal (a cookie,
|
||||
a page global) or the network, neither of which needs a rendered page.
|
||||
Measured 2026-09-12: X, Instagram and Threads all answer correctly with
|
||||
`document.visibilityState == "hidden"`. It is not for the post flows —
|
||||
those drive dialogs and file inputs, which need the foreground.
|
||||
"""
|
||||
try:
|
||||
tab = await self.attach_existing(url_contains)
|
||||
await tab.activate()
|
||||
if activate:
|
||||
await tab.activate()
|
||||
return tab, True
|
||||
except CDPError:
|
||||
tab = await self.open_tab(url)
|
||||
|
||||
Reference in New Issue
Block a user