From cdcb61fcd617f141d9b279619022b3bb86820e69 Mon Sep 17 00:00:00 2001 From: sevenhill Date: Sat, 4 Jul 2026 10:28:47 +0300 Subject: [PATCH] Stabilize MAX composer focus for sending --- worker/src/server.js | 52 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/worker/src/server.js b/worker/src/server.js index 4dbae7a..7d574dd 100644 --- a/worker/src/server.js +++ b/worker/src/server.js @@ -2194,6 +2194,10 @@ async function sendTextAndConfirm(p, externalChatId, text) { } async function fillComposerText(p, text, clearFirst) { + if (clearFirst && await fillComposerViaLocator(p, text)) { + return true; + } + for (let attempt = 0; attempt < 2; attempt++) { if (!(await focusComposer(p))) { break; @@ -2246,6 +2250,40 @@ async function fillComposerText(p, text, clearFirst) { return false; } +async function fillComposerViaLocator(p, text) { + const selectors = [ + "[data-testid='composer'] [role='textbox']", + "[data-testid='composer'] [contenteditable='true']", + "[class*='composer' i] [role='textbox']", + "[class*='composer' i] [contenteditable='true']", + "[class*='composer' i] [class*='contenteditable' i]", + "[role='textbox'][class*='contenteditable' i]" + ]; + + for (const selector of selectors) { + try { + const composer = p.locator(selector).last(); + if ((await composer.count()) === 0) { + continue; + } + + await composer.scrollIntoViewIfNeeded({ timeout: 2000 }).catch(() => {}); + await composer.click({ timeout: 3000 }); + await composer.fill("", { timeout: 3000 }); + await composer.fill(text, { timeout: 3000 }); + await p.waitForTimeout(200); + const currentText = await readComposerText(p); + if (currentText !== null && messageTextMatches(currentText, text)) { + return true; + } + } catch { + // Try the next composer shape. + } + } + + return false; +} + async function focusComposer(p) { const point = await p.evaluate(() => { const cleanText = (value) => String(value || "") @@ -2301,6 +2339,7 @@ async function focusComposer(p) { .map((element) => { const rect = element.getBoundingClientRect(); return { + element, x: Math.round(rect.left + rect.width / 2), y: Math.round(rect.top + rect.height / 2), bottom: Math.round(rect.bottom), @@ -2308,7 +2347,18 @@ async function focusComposer(p) { }; }) .sort((a, b) => b.bottom - a.bottom || b.area - a.area); - return candidates[0] || { + const candidate = candidates[0]; + if (candidate?.element instanceof HTMLElement) { + candidate.element.scrollIntoView({ block: "center", inline: "nearest" }); + candidate.element.focus({ preventScroll: true }); + const rect = candidate.element.getBoundingClientRect(); + return { + x: Math.round(rect.left + rect.width / 2), + y: Math.round(rect.top + rect.height / 2) + }; + } + + return { x: Math.round(window.innerWidth * 0.55), y: Math.round(window.innerHeight - 40) };