您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Универсальный скрипт: надёжно перезагружает / пересоздаёт Google reCAPTCHA iframe (включая динамические сайты). НЕ РЕШАЕТ капчу — только обновляет/рестартует виджет. Работает на всех сайтах; имеет UI, настройки и persist через localStorage.
// ==UserScript== // @name reCAPTCHA Robust Auto-Refresh — GLOBAL // @namespace https://greasyfork.org/users/1231264 // @version 2.0.0 // @description Универсальный скрипт: надёжно перезагружает / пересоздаёт Google reCAPTCHA iframe (включая динамические сайты). НЕ РЕШАЕТ капчу — только обновляет/рестартует виджет. Работает на всех сайтах; имеет UI, настройки и persist через localStorage. // @match *://*/* // @grant none // @run-at document-end // ==/UserScript== (function () { 'use strict'; /***************** Настройки по умолчанию (можно менять в UI) *****************/ const DEFAULTS = { DEFAULT_REFRESH_SECONDS: 60, // базовый интервал (секунды) RANDOM_JITTER_SECONDS: 8, // рандом для интервала (сек) MIN_TOKEN_LENGTH: 30, // минимальная длина g-recaptcha-response считаем решённой DEBUG: false // логирование }; const STORAGE_KEY = 'rc_auto_global_settings_v2'; /******************************************************************************/ // загрузка/сохранение настроек function loadSettings() { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return Object.assign({}, DEFAULTS, { AUTO_ENABLED: true }); const parsed = JSON.parse(raw); return Object.assign({}, DEFAULTS, parsed); } catch (e) { console.error('[rc-auto] failed to load settings', e); return Object.assign({}, DEFAULTS, { AUTO_ENABLED: true }); } } function saveSettings(obj){ try { localStorage.setItem(STORAGE_KEY, JSON.stringify(obj)); } catch(e){ console.error('[rc-auto] failed to save settings', e); } } let settings = loadSettings(); // ensure AUTO_ENABLED default true if not present if (typeof settings.AUTO_ENABLED === 'undefined') settings.AUTO_ENABLED = true; // лог-функции function log(...args){ if (settings.DEBUG) console.log('[rc-auto]', ...args); } function info(...args){ console.log('[rc-auto]', ...args); } function warn(...args){ console.warn('[rc-auto]', ...args); } // state let autoTimer = null; let isRunning = false; let lastReloadTs = 0; let observer = null; const MANUAL_BUTTON_ID = 'rc-auto-refresh-btn-global'; const SETTINGS_PANEL_ID = 'rc-auto-settings-panel'; function nowMs(){ return Date.now(); } // Поиск iframe reCAPTCHA function findRecaptchaIframes(root = document) { return Array.from(root.querySelectorAll('iframe[src*="recaptcha"], iframe[src*="google.com/recaptcha"], iframe[src*="recaptcha.net"]')); } // Проверка видимости элемента function isVisible(el){ try { const r = el.getBoundingClientRect(); const style = window.getComputedStyle(el); return r.width > 0 && r.height > 0 && style.visibility !== 'hidden' && style.display !== 'none' && el.offsetParent !== null; } catch (e) { return false; } } // Проверка решённости капчи function isCaptchaSolved() { try { const areas = document.querySelectorAll('textarea[name="g-recaptcha-response"], input[name="g-recaptcha-response"]'); for (const a of areas) { if (a && a.value && a.value.trim().length >= settings.MIN_TOKEN_LENGTH) return true; } if (document.querySelector('.recaptcha-checkbox-checked')) return true; return false; } catch (e) { log('isCaptchaSolved error', e); return false; } } // Получить базовый src без query/hash function baseSrcFrom(frame){ try { const url = frame.getAttribute('src') || ''; return url.split('#')[0].split('?')[0]; } catch(e){ return null; } } // Пересоздать iframe (клонирование + новый src с reload) function recreateIframe(frame){ try { const parent = frame.parentNode; if (!parent) return false; const base = baseSrcFrom(frame); if (!base) return false; const newFrame = document.createElement('iframe'); for (const attr of frame.attributes) { if (attr.name === 'src') continue; newFrame.setAttribute(attr.name, attr.value); } const ts = nowMs(); const reloadParam = 'reload=' + ts; newFrame.src = base + (base.includes('?') ? '&' : '?') + reloadParam + '&hl=' + (navigator.language || 'en'); parent.insertBefore(newFrame, frame); setTimeout(()=>{ try { parent.removeChild(frame); } catch(e){} }, 500); info('Пересоздан iframe reCAPTCHA:', newFrame.src); lastReloadTs = ts; return true; } catch (e) { warn('recreateIframe error', e); return false; } } // Попытка простого reload (переназначение src + reload param) function reloadFrame(frame){ try { const base = baseSrcFrom(frame); if (!base) return false; const ts = nowMs(); frame.src = base + '?reload=' + ts + '&hl=' + (navigator.language || 'en'); lastReloadTs = ts; info('Перезагружен iframe:', frame.src); return true; } catch(e){ warn('reloadFrame error', e); return false; } } // Попробовать grecaptcha.reset() если доступен function tryGreCaptchaReset(){ try { if (window.grecaptcha && typeof window.grecaptcha.reset === 'function') { window.grecaptcha.reset(); info('grecaptcha.reset() выполнен'); lastReloadTs = nowMs(); return true; } } catch (e) { log('grecaptcha.reset threw', e); } return false; } // Основной flow перезагрузки: сначала grecaptcha.reset, затем reload, иначе recreate function refreshAllCaptchaWidgets({force=false} = {}){ if (isCaptchaSolved()){ info('Token найден — автообновление остановлено'); stopAuto(); return; } const minIntervalMs = 6000; // минимум между reload if (!force && nowMs() - lastReloadTs < minIntervalMs) { log('Слишком недавно выполняли reload, пропускаем'); return; } if (tryGreCaptchaReset()) return; const frames = findRecaptchaIframes(document).filter(isVisible); if (frames.length === 0) { log('reCAPTCHA iframe не найден (видимых):', frames.length); return; } frames.forEach(f => { const ok = reloadFrame(f); if (!ok) recreateIframe(f); }); } // Авто-таймер с джиттером function startAuto(){ if (isRunning) return; isRunning = true; info('Запуск авто-обновления reCAPTCHA (интервал', settings.DEFAULT_REFRESH_SECONDS, 'с ±', settings.RANDOM_JITTER_SECONDS, 'с)'); refreshAllCaptchaWidgets(); function scheduleNext(){ const jitter = Math.floor(Math.random() * (settings.RANDOM_JITTER_SECONDS * 1000)); const interval = settings.DEFAULT_REFRESH_SECONDS * 1000 + jitter; autoTimer = setTimeout(()=>{ if (!isRunning) return; if (isCaptchaSolved()) { info('Token найден — остановка'); stopAuto(); return; } refreshAllCaptchaWidgets(); scheduleNext(); }, interval); } scheduleNext(); } function stopAuto(){ if (!isRunning) return; isRunning = false; if (autoTimer) { clearTimeout(autoTimer); autoTimer = null; } info('Auto-обновление остановлено'); } // UI: кнопка Refresh function addManualButton(){ try { if (document.getElementById(MANUAL_BUTTON_ID)) return; const btn = document.createElement('button'); btn.id = MANUAL_BUTTON_ID; btn.textContent = '⟳ Refresh CAPTCHA'; Object.assign(btn.style, { position: 'fixed', right: '12px', bottom: '12px', zIndex: 2147483647, padding: '10px 12px', fontSize: '13px', borderRadius: '8px', boxShadow: '0 2px 6px rgba(0,0,0,0.3)', border: 'none', cursor: 'pointer', background: '#0a84ff', color: '#fff', }); btn.title = 'Ручная перезагрузка reCAPTCHA iframe (НЕ решает капчу)'; btn.addEventListener('click', (e)=>{ e.preventDefault(); info('Ручной refresh нажали'); refreshAllCaptchaWidgets({force:true}); }); document.body.appendChild(btn); } catch(e){ log('addManualButton err', e); } } // UI: панель настроек function addSettingsPanel(){ try { if (document.getElementById(SETTINGS_PANEL_ID)) return; const panel = document.createElement('div'); panel.id = SETTINGS_PANEL_ID; Object.assign(panel.style, { position: 'fixed', right: '12px', bottom: '62px', zIndex: 2147483647, padding: '10px', background: 'rgba(255,255,255,0.98)', color: '#000', borderRadius: '8px', boxShadow: '0 2px 8px rgba(0,0,0,0.25)', fontSize: '13px', minWidth: '230px', }); panel.innerHTML = ` <div style="margin-bottom:8px;font-weight:600">reCAPTCHA Auto (global)</div> <label style="display:block;margin-bottom:6px"> <input type="checkbox" id="rc_auto_enabled"> Авто-обновление </label> <label style="display:block;margin-bottom:6px"> Интервал (сек): <input id="rc_auto_interval" type="number" style="width:70px" min="10"> </label> <label style="display:block;margin-bottom:6px"> Джиттер (сек): <input id="rc_auto_jitter" type="number" style="width:50px" min="0"> </label> <label style="display:block;margin-bottom:6px"> <input type="checkbox" id="rc_auto_debug"> Режим отладки (логи) </label> <div style="display:flex;gap:8px;margin-top:8px"> <button id="rc_auto_save" style="flex:1">Сохранить</button> <button id="rc_auto_reset" style="flex:1">Сбросить</button> </div> <div style="margin-top:8px;font-size:12px;color:#666">Token: <span id="rc_auto_token_state">—</span></div> `; document.body.appendChild(panel); // заполнение значений document.getElementById('rc_auto_enabled').checked = !!settings.AUTO_ENABLED; document.getElementById('rc_auto_interval').value = settings.DEFAULT_REFRESH_SECONDS; document.getElementById('rc_auto_jitter').value = settings.RANDOM_JITTER_SECONDS; document.getElementById('rc_auto_debug').checked = !!settings.DEBUG; updateTokenState(); document.getElementById('rc_auto_save').addEventListener('click', ()=>{ settings.AUTO_ENABLED = !!document.getElementById('rc_auto_enabled').checked; settings.DEFAULT_REFRESH_SECONDS = Math.max(10, parseInt(document.getElementById('rc_auto_interval').value || settings.DEFAULT_REFRESH_SECONDS, 10)); settings.RANDOM_JITTER_SECONDS = Math.max(0, parseInt(document.getElementById('rc_auto_jitter').value || settings.RANDOM_JITTER_SECONDS, 10)); settings.DEBUG = !!document.getElementById('rc_auto_debug').checked; saveSettings(settings); info('Настройки сохранены', settings); if (settings.AUTO_ENABLED) startAuto(); else stopAuto(); }); document.getElementById('rc_auto_reset').addEventListener('click', ()=>{ settings = Object.assign({}, DEFAULTS, { AUTO_ENABLED: true }); saveSettings(settings); // обновить UI document.getElementById('rc_auto_enabled').checked = true; document.getElementById('rc_auto_interval').value = settings.DEFAULT_REFRESH_SECONDS; document.getElementById('rc_auto_jitter').value = settings.RANDOM_JITTER_SECONDS; document.getElementById('rc_auto_debug').checked = settings.DEBUG; info('Настройки сброшены'); startAuto(); }); } catch (e) { log('addSettingsPanel err', e); } } // MutationObserver — наблюдаем за DOM, если появится капча — запускаем refresh function startDomObserver(){ if (observer) return; observer = new MutationObserver((mutations) => { let found = false; for (const m of mutations){ if (m.addedNodes && m.addedNodes.length){ for (const n of m.addedNodes){ if (!(n instanceof HTMLElement)) continue; if (n.querySelector && n.querySelector('iframe[src*="recaptcha"], iframe[src*="google.com/recaptcha"], iframe[src*="recaptcha.net"]')) { found = true; break; } if (n.classList && (n.classList.contains('g-recaptcha') || n.className.includes('recaptcha') || n.className.includes('grecaptcha'))) { found = true; break; } } } if (found) break; } if (found){ log('MutationObserver: найдены элементы capcha — выполняем refresh'); setTimeout(()=> refreshAllCaptchaWidgets(), 600); } }); observer.observe(document.documentElement || document.body, { childList: true, subtree: true }); log('MutationObserver запущен'); } // Показ состояния токена в UI function updateTokenState(){ try { const el = document.getElementById('rc_auto_token_state'); if (!el) return; el.textContent = isCaptchaSolved() ? 'НАЙДЕН' : '—'; } catch (e) { /* ignore */ } } // Инициализация UI и логики function init(){ try { addManualButton(); addSettingsPanel(); startDomObserver(); // автозапуск если включено и на странице есть признаки капчи function pageHasCaptchaHint() { try { if (document.querySelector('iframe[src*="recaptcha"], iframe[src*="google.com/recaptcha"], iframe[src*="recaptcha.net"]')) return true; if (document.querySelector('.g-recaptcha')) return true; if (document.querySelector('[data-sitekey]')) return true; if (/recaptcha|g-recaptcha|anti ?bot|captcha/i.test(document.body.innerText)) return true; } catch (e) {} return false; } if (settings.AUTO_ENABLED && pageHasCaptchaHint()) startAuto(); // при клике — попробовать стартовать авто (если пользователь взаимодействует и капча может появиться) document.addEventListener('click', function onFirstClick(){ setTimeout(()=> { if (settings.AUTO_ENABLED && pageHasCaptchaHint()) startAuto(); }, 700); document.removeEventListener('click', onFirstClick); }, { once: true }); // периодически обновлять индикатор токена setInterval(updateTokenState, 1500); } catch (e) { warn('init error', e); } } // cleanup window.addEventListener('beforeunload', ()=>{ stopAuto(); if (observer) observer.disconnect(); }); // старт init(); })();