From 2b127d070be9b6e574814e0485190bcbcd744d4a Mon Sep 17 00:00:00 2001 From: chick Date: Sun, 31 May 2026 17:23:30 +0800 Subject: [PATCH] feat: auto submit after filling phone --- README.md | 6 +++--- content.js | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 73215f4..b982060 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ SMSBower Phone Fill Tool -用途:点击扩展图标后,在当前网页右上角打开一个常驻悬浮窗。点一次“获取并填入”就获取一个 SMSBower 手机号,自动填入当前页面最像手机号的输入框,并复制到剪贴板。再次获取会先释放上一个激活,再拿新号替换页面输入框。 +用途:点击扩展图标后,在当前网页右上角打开一个常驻悬浮窗。点一次“获取并填入”就获取一个 SMSBower 手机号,自动填入当前页面最像手机号的输入框、复制到剪贴板,并自动点击页面上的下一步/发送验证码按钮。再次获取会先释放上一个激活,再拿新号替换页面输入框并自动提交。 本版已集成 FlowPilot 同款自动切号机制: - 悬浮窗打开后默认开启“自动切号:开”。 - 页面提示“该电话/手机号已被使用、已绑定、已注册”时,只要确认是当前新号码触发的错误,插件会自动切换下一个号码;旧号按被拒原因释放,新号自动填入并复制。 - 页面提示“无法向此电话号码发送验证码”等发送失败时,插件会自动按可恢复失败换号。 - “检测报错换号”和“已使用换号”仍保留为手动兜底按钮。 -- 仍然只负责填号/查码/复制,不自动点击目标页面继续按钮。 +- 填号后会自动寻找并点击目标页面上的“下一步/继续/发送验证码/提交”等按钮;如果找不到按钮,会尝试提交表单或发送 Enter。 安装/更新: 1. 打开 Chrome/Edge 扩展管理页。 @@ -20,7 +20,7 @@ SMSBower Phone Fill Tool 2. 点浏览器工具栏里的“SMSBower 悬浮填号”扩展图标。 3. 页面右上角会出现悬浮窗,可拖动。 4. 填 SMSBower API Key、项目代码、价格上下限、国家顺序。 -5. 顶部“获取并填入”会立即拿号并填入。 +5. 顶部“获取并填入”会立即拿号、填入、复制,并自动提交/点击发送验证码。 6. 再点一次“获取并填入”会释放上一个激活,替换输入框为新手机号。 7. 如果目标页面拒绝号码,保持悬浮窗打开即可:插件会自动扫描页面错误文本并切换下一个号码。 - “自动切号:开/关”可以临时启停自动扫描; diff --git a/content.js b/content.js index 872fc34..3794caa 100644 --- a/content.js +++ b/content.js @@ -79,7 +79,58 @@ const input = findBestInput(); if (!input) throw new Error('当前页面没有找到可填写的输入框。请先点一下目标输入框再获取。'); setValue(input, phoneNumber); - return { phoneNumber, tag: input.tagName, name: input.name || '', id: input.id || '' }; + return { phoneNumber, input, tag: input.tagName, name: input.name || '', id: input.id || '' }; + } + + function scoreSubmitButton(button, input) { + if (!button || panel?.contains(button)) return -1000; + const style = window.getComputedStyle(button); + const rect = button.getBoundingClientRect(); + if (button.disabled || style.visibility === 'hidden' || style.display === 'none' || rect.width <= 0 || rect.height <= 0) return -1000; + const text = [ + button.innerText, button.textContent, button.value, button.name, button.id, + button.getAttribute('aria-label'), button.getAttribute('title') + ].join(' ').toLowerCase(); + let score = 0; + if (/下一步|继续|发送验证码|获取验证码|发送代码|发送短信|验证|提交|next|continue|send\s*(code|sms)?|verify|submit/.test(text)) score += 100; + if (/取消|返回|back|cancel|关闭|close|skip|跳过|resend|重发/.test(text)) score -= 140; + if (button.type === 'submit') score += 35; + if (input) { + const inputRect = input.getBoundingClientRect(); + const dy = rect.top - inputRect.bottom; + const dx = Math.abs((rect.left + rect.right) / 2 - (inputRect.left + inputRect.right) / 2); + if (dy >= -20 && dy < 260) score += Math.max(0, 60 - dy / 5); + if (dx < 360) score += Math.max(0, 30 - dx / 20); + } + return score; + } + + function findSubmitButton(input) { + const formButton = input?.form?.querySelector('button[type="submit"], input[type="submit"]'); + const candidates = Array.from(document.querySelectorAll('button, input[type="button"], input[type="submit"], [role="button"]')) + .filter((el) => !panel || !panel.contains(el)); + if (formButton && !candidates.includes(formButton)) candidates.unshift(formButton); + const ranked = candidates.map((el) => ({ el, score: scoreSubmitButton(el, input) })).sort((a, b) => b.score - a.score); + return ranked[0]?.score > 30 ? ranked[0].el : null; + } + + async function autoSubmitPhone(input) { + await sleep(250); + const button = findSubmitButton(input); + if (button) { + button.scrollIntoView?.({ block: 'center', inline: 'center' }); + button.click(); + return { method: 'button', text: String(button.innerText || button.textContent || button.value || button.getAttribute('aria-label') || '').trim().slice(0, 40) }; + } + const form = input?.form; + if (form) { + if (typeof form.requestSubmit === 'function') form.requestSubmit(); + else form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); + return { method: 'form' }; + } + input?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', bubbles: true })); + input?.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', bubbles: true })); + return { method: 'enter' }; } function send(type, payload = {}) { @@ -166,13 +217,14 @@ const res = await send('FETCH_NEXT_PHONE', { reason, releaseAction }); const phone = res.activation.phoneNumber; await copyText(phone); - fillPhone(phone); + const filled = fillPhone(phone); $('.sb-current-phone').textContent = phone; lastErroredPhoneNumber = ''; $('.sb-current-id').textContent = res.activation.activationId; const codeNode = $('.sb-current-code'); if (codeNode) codeNode.textContent = '无'; - setStatus(`已切换、填入并复制:${phone}`); + const submit = await autoSubmitPhone(filled.input); + setStatus(`已切换、填入、复制并自动提交:${phone}${submit.text ? `(${submit.text})` : ''}`); } catch (error) { setStatus(error.message || String(error), true); } finally {