Вы, случайно, не робот?

Автоматическое решение капчи ✅

да я да да

Ну что, опять какая-то новая херня бесячая появилась на ДТФ? Классика.

С недавнего времени я заметил, что капчи стали постоянно появляться. Раздражает. Что за дискриминация против роботов? А что если я идентифицирую себя как робот?

Ну, пришлось добавлять новую функцию в расширение, что поделать. А ещё в этот раз я решил сделать версию для tampermonkey для тех, кто не хочет расширение ставить.

Долго мусолить не буду, потому что это тоже внеплановый пост.

Функция "Решать капчу"

функция решать капчу решает капчи
функция решать капчу решает капчи

Находится внизу категории "Контент и отображение".

Учтите, что для её работы необходимо будет дать разрешение на доступ к сервису Google, потому что используется их капча. При активации функции браузер сам запросит разрешение.

Это обновление появится позже среди дня сегодня (скорее всего).
Версия 1.9.0

Как работает функция

Да просто работает и всё. Что за тупые подзаголовки пошли.

Ссылки на расширение:

Скрипт для Tampermonkey

Что это? Это расширение, которое позволяет запускать пользовательские скрипты.

Как им пользоваться? Просто установить и вставить код, который я дам ниже.

Важный момент: этот код работает исключительно на ДТФ. Он не будет решать капчи на других сайтах! Почему? Потому что это не бесплатное удовольствие (для меня). Если хотите больше — пишите в ЛС, договоримся. И не надо ковырять мою апишку!

На этом внеплановый пост подошёл к концу. Пишите, что думаете и т. д. Надо ли это вообще кому-то, кроме меня? А вдруг эти капчи вижу только я? Ну и ладно. Я пошёл.

// ==UserScript== // @name DTF reCAPTCHA Solver // @namespace tampermonkey // @version 1.0 // @author Nikos // @description Автоматически решает капчу на ДТФ // @match https://www.google.com/recaptcha/api2/anchor* // @match https://www.google.com/recaptcha/api2/bframe* // @grant none // @run-at document-end // ==/UserScript== 'use strict'; const SOLVER_ENDPOINT = 'https://api.dtfrandomizer.xyz/api/captcha/solve'; const delay = (ms = 1000) => new Promise(r => setTimeout(r, ms)); const waitForElement = (selector, predicate = () => true, timeout = 8000) => { return new Promise((resolve, reject) => { const check = () => { const el = document.querySelector(selector); return el && predicate(el) ? el : null; }; const found = check(); if (found) return resolve(found); const observer = new MutationObserver(() => { const el = check(); if (el) { observer.disconnect(); resolve(el); } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['disabled', 'aria-disabled'], }); setTimeout(() => { observer.disconnect(); reject(new Error(`Timed out waiting for: ${selector}`)); }, timeout); }); }; const mountOverlay = () => { const style = document.createElement('style'); style.textContent = ` @keyframes solver-spin { to { transform: rotate(360deg); } } #solver-overlay { position: fixed; inset: 0; z-index: 99999; backdrop-filter: blur(4px); background: rgba(255, 255, 255, 0.45); display: flex; align-items: center; justify-content: center; } #solver-spinner { width: 38px; height: 38px; border-radius: 50%; border: 3px solid rgba(0, 0, 0, 0.12); border-top-color: #4285f4; animation: solver-spin 0.7s linear infinite; } `; const overlay = document.createElement('div'); overlay.id = 'solver-overlay'; overlay.innerHTML = '<div id="solver-spinner"></div>'; document.head.appendChild(style); document.body.appendChild(overlay); }; const unmountOverlay = () => { document.getElementById('solver-overlay')?.remove(); }; const transcribeAudio = async audioUrl => { const sitekey = new URLSearchParams(location.search).get('k'); const audioBuffer = await fetch(audioUrl).then(r => r.arrayBuffer()); const audioBlob = new Blob([audioBuffer], { type: 'audio/mpeg' }); const payload = new FormData(); payload.append('audio', audioBlob, 'challenge.mp3'); payload.append('sitekey', sitekey); const res = await fetch(SOLVER_ENDPOINT, { method: 'POST', body: payload }); if (!res.ok) throw new Error(`Solver returned HTTP ${res.status}`); const { text } = await res.json(); return text.trim().toLowerCase(); }; const solveViaCheckbox = async () => { const anchor = await waitForElement('#recaptcha-anchor'); anchor.click(); }; const solveViaAudio = async () => { try { const audioButton = await waitForElement( '#recaptcha-audio-button', el => !el.disabled && el.getAttribute('aria-disabled') !== 'true' ); await delay(200) audioButton.click(); const audioSource = await waitForElement('#audio-source'); mountOverlay(); const solution = await transcribeAudio(audioSource.src); const responseInput = await waitForElement('#audio-response'); await delay(200) responseInput.value = solution; responseInput.dispatchEvent(new Event('input', { bubbles: true })); responseInput.dispatchEvent(new Event('change', { bubbles: true })); await waitForElement( '#recaptcha-verify-button', el => !el.disabled && el.getAttribute('aria-disabled') !== 'true' ); await delay(200) document.querySelector('#recaptcha-verify-button').click(); } catch (error) { console.warn('[solver] failed:', error?.message); } finally { unmountOverlay(); } }; if (location.href.includes('/api2/anchor')) solveViaCheckbox(); else if (location.href.includes('/api2/bframe')) solveViaAudio();
111
50
32
6
4
1
1