#!/usr/bin/env python3 """Strict 2925/OpenAI email resend cadence runner. Cadence encoded from BOSS correction: for each resend slot: refresh 2925 Inbox + Junk for N rounds, sleeping between rounds only then click OpenAI resend once This script is intentionally env-driven and JSONL-only. It does not buy SMS. Required environment: RUN_JSON=/tmp/codex_2925_luban_uk_run.json # contains {"email":..., "alias":...} Optional environment: MAIL_CDP=http://127.0.0.1:9227 OPENAI_CDP=http://127.0.0.1:9228 START_RESEND_DONE=0 TARGET_RESENDS=10 REFRESH_ROUNDS=3 SLEEP_BETWEEN_REFRESH_ROUNDS=15 CODE_PATH=/tmp/openai_2925_email_code.txt """ import itertools import json import os import pathlib import time import urllib.request import websocket RUN_JSON = pathlib.Path(os.environ.get("RUN_JSON", "/tmp/codex_2925_luban_uk_run.json")) RUN = json.loads(RUN_JSON.read_text()) ACCOUNT = RUN["email"] ALIAS = RUN["alias"] LOCAL = ALIAS.split("@")[0].lower() MAIL_CDP = os.environ.get("MAIL_CDP", "http://127.0.0.1:9227") OPENAI_CDP = os.environ.get("OPENAI_CDP", "http://127.0.0.1:9228") START_RESEND_DONE = int(os.environ.get("START_RESEND_DONE", "0")) TARGET_RESENDS = int(os.environ.get("TARGET_RESENDS", "10")) REFRESH_ROUNDS = int(os.environ.get("REFRESH_ROUNDS", "3")) SLEEP_BETWEEN_REFRESH_ROUNDS = int(os.environ.get("SLEEP_BETWEEN_REFRESH_ROUNDS", "15")) CODE_PATH = pathlib.Path(os.environ.get("CODE_PATH", "/tmp/openai_2925_email_code.txt")) FOLDERS = [ ("inbox", "https://2925.com/#/mailList?type=%E6%94%B6%E4%BB%B6%E7%AE%B1"), ("junk", "https://2925.com/#/mailList?type=%E5%9E%83%E5%9C%BE%E7%AE%B1"), ] def log(obj): print(json.dumps({**obj, "ts": int(time.time())}, ensure_ascii=False), flush=True) def tabs(cdp): return json.loads(urllib.request.urlopen(cdp + "/json", timeout=10).read().decode()) def connect(cdp, pred): pages = [t for t in tabs(cdp) if t.get("type") == "page"] selected = next((t for t in pages if pred(t)), None) or (pages[0] if pages else None) if not selected: raise RuntimeError(f"no_page_target:{cdp}") ws = websocket.create_connection(selected["webSocketDebuggerUrl"], timeout=20) counter = itertools.count(1) def call(method, params=None, timeout=45): msg_id = next(counter) ws.send(json.dumps({"id": msg_id, "method": method, "params": params or {}})) end = time.time() + timeout while time.time() < end: msg = json.loads(ws.recv()) if msg.get("id") == msg_id: if "error" in msg: raise RuntimeError(msg["error"]) return msg.get("result", {}) raise TimeoutError(method) call("Page.enable") call("Runtime.enable") return call def evaluate(call, js, await_promise=False, timeout=45): result = call( "Runtime.evaluate", {"expression": js, "awaitPromise": await_promise, "returnByValue": True}, timeout, ) return result.get("result", {}).get("value") def refresh_once(folder, url, resend_index, refresh_round): call = connect(MAIL_CDP, lambda t: "2925.com" in (t.get("url") or "")) call("Page.navigate", {"url": url}) time.sleep(2) js = r'''(async(local,account)=>{ const sleep=ms=>new Promise(r=>setTimeout(r,ms)); const click=e=>{if(!e)return false; e.dispatchEvent(new MouseEvent('mousedown',{bubbles:true})); e.dispatchEvent(new MouseEvent('mouseup',{bubbles:true})); e.click(); return true;}; const refreshButtons=[...document.querySelectorAll('button,.el-button,a,span,div')].filter(e=>(e.innerText||e.textContent||'').trim()==='刷新'); const clicked=click(refreshButtons[refreshButtons.length-1]||refreshButtons[0]); await sleep(2500); const txt=document.body?.innerText||''; const low=txt.toLowerCase(); const emails=[...new Set([...txt.matchAll(/[A-Za-z0-9._%+-]+@2925\.com/g)].map(m=>m[0].toLowerCase()))]; const lines=txt.split(/\n+/).map(s=>s.trim()).filter(Boolean); const snippets=[]; for(let i=0;i[...s.matchAll(/(?m[1])))]; return {clicked,emails,accountOk:emails.includes(account.toLowerCase()),hasLocal:low.includes(local),hasOpenAI:/OpenAI|ChatGPT|验证码|verification|code/i.test(txt),codes}; })(LOCAL,ACCOUNT)'''.replace("LOCAL", json.dumps(LOCAL)).replace("ACCOUNT", json.dumps(ACCOUNT)) val = evaluate(call, js, True) or {} log({ "phase": "mail_refresh", "resend_index": resend_index, "refresh_round": refresh_round, "folder": folder, "clicked": val.get("clicked"), "accountOk": val.get("accountOk"), "hasLocal": val.get("hasLocal"), "hasOpenAI": val.get("hasOpenAI"), "codesCount": len(val.get("codes") or []), "emails": val.get("emails"), }) if not val.get("accountOk"): log({"phase": "account_mismatch", "expected": ACCOUNT, "emails": val.get("emails")}) raise SystemExit(4) if val.get("codes"): CODE_PATH.write_text(val["codes"][0]) log({"phase": "current_alias_code_saved", "resend_index": resend_index, "folder": folder}) return True return False def click_resend(resend_index): call = connect(OPENAI_CDP, lambda t: "auth.openai.com" in (t.get("url") or "")) res = evaluate(call, r'''(async()=>{ const sleep=ms=>new Promise(r=>setTimeout(r,ms)); const btn=[...document.querySelectorAll('button,a')].find(e=>/重新发送|Resend/i.test(e.innerText||e.textContent||'')); if(btn){btn.scrollIntoView({block:'center'}); btn.click(); await sleep(2500);} return {clicked:!!btn,href:location.href,body:(document.body?.innerText||'').slice(0,260)}; })()''', True) or {} log({"phase": "openai_resend", "resend_index": resend_index, "clicked": res.get("clicked"), "href": res.get("href")}) if not res.get("clicked"): log({"phase": "openai_resend_not_found", "resend_index": resend_index, "body": res.get("body")}) raise SystemExit(5) def main(): log({ "phase": "strict_resend_cadence_start", "alias": ALIAS, "account": ACCOUNT, "start_resend_done": START_RESEND_DONE, "target_resends": TARGET_RESENDS, "refresh_rounds": REFRESH_ROUNDS, }) for resend_index in range(START_RESEND_DONE + 1, TARGET_RESENDS + 1): log({"phase": "pre_resend_refresh_block_start", "resend_index": resend_index}) for refresh_round in range(1, REFRESH_ROUNDS + 1): for name, url in FOLDERS: if refresh_once(name, url, resend_index, refresh_round): return 0 if refresh_round < REFRESH_ROUNDS: time.sleep(SLEEP_BETWEEN_REFRESH_ROUNDS) click_resend(resend_index) log({"phase": "no_code_after_target_resends", "alias": ALIAS, "total_resends": TARGET_RESENDS}) return 2 if __name__ == "__main__": raise SystemExit(main())