Spaces:
Paused
Paused
Update server.js
Browse files
server.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
| 1 |
import express from 'express';
|
| 2 |
import { chromium } from 'playwright-core';
|
| 3 |
import cors from 'cors';
|
| 4 |
-
import {
|
| 5 |
-
import { promises as fs } from 'fs';
|
| 6 |
-
import { tmpdir } from 'os';
|
| 7 |
-
import { join } from 'path';
|
| 8 |
|
| 9 |
const app = express();
|
| 10 |
const PORT = process.env.PORT || 7860;
|
|
@@ -12,162 +9,6 @@ const PORT = process.env.PORT || 7860;
|
|
| 12 |
app.use(cors());
|
| 13 |
app.use(express.json());
|
| 14 |
|
| 15 |
-
async function solveRecaptcha(page) {
|
| 16 |
-
const startTime = Date.now();
|
| 17 |
-
|
| 18 |
-
await page.waitForTimeout(3000);
|
| 19 |
-
|
| 20 |
-
const frames = page.frames();
|
| 21 |
-
let recaptchaFrame = null;
|
| 22 |
-
let bframe = null;
|
| 23 |
-
|
| 24 |
-
for (const frame of frames) {
|
| 25 |
-
const url = frame.url();
|
| 26 |
-
if (url.includes('google.com/recaptcha/api2/anchor')) {
|
| 27 |
-
recaptchaFrame = frame;
|
| 28 |
-
}
|
| 29 |
-
if (url.includes('google.com/recaptcha/api2/bframe')) {
|
| 30 |
-
bframe = frame;
|
| 31 |
-
}
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
if (!recaptchaFrame) {
|
| 35 |
-
await page.waitForTimeout(2000);
|
| 36 |
-
const updatedFrames = page.frames();
|
| 37 |
-
for (const frame of updatedFrames) {
|
| 38 |
-
const url = frame.url();
|
| 39 |
-
if (url.includes('google.com/recaptcha/api2/anchor')) {
|
| 40 |
-
recaptchaFrame = frame;
|
| 41 |
-
break;
|
| 42 |
-
}
|
| 43 |
-
}
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
if (!recaptchaFrame) {
|
| 47 |
-
throw new Error('reCAPTCHA frame not found');
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
const checkbox = await recaptchaFrame.$('#recaptcha-anchor');
|
| 51 |
-
if (!checkbox) {
|
| 52 |
-
throw new Error('reCAPTCHA checkbox not found');
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
await checkbox.click();
|
| 56 |
-
await page.waitForTimeout(2000);
|
| 57 |
-
|
| 58 |
-
const isChecked = await recaptchaFrame.$eval('#recaptcha-anchor', el =>
|
| 59 |
-
el.getAttribute('aria-checked') === 'true'
|
| 60 |
-
);
|
| 61 |
-
|
| 62 |
-
if (isChecked) {
|
| 63 |
-
console.log('[Solver] reCAPTCHA solved with checkbox click');
|
| 64 |
-
return true;
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
await page.waitForTimeout(2000);
|
| 68 |
-
const bframes = page.frames().filter(f => f.url().includes('google.com/recaptcha/api2/bframe'));
|
| 69 |
-
|
| 70 |
-
if (bframes.length === 0) {
|
| 71 |
-
throw new Error('Challenge frame not found');
|
| 72 |
-
}
|
| 73 |
-
|
| 74 |
-
bframe = bframes[0];
|
| 75 |
-
|
| 76 |
-
const audioButton = await bframe.$('#recaptcha-audio-button');
|
| 77 |
-
if (!audioButton) {
|
| 78 |
-
throw new Error('Audio button not found');
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
await audioButton.click();
|
| 82 |
-
await page.waitForTimeout(2000);
|
| 83 |
-
|
| 84 |
-
const audioSource = await bframe.$('#audio-source');
|
| 85 |
-
if (!audioSource) {
|
| 86 |
-
throw new Error('Audio source not found');
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
const audioUrl = await audioSource.getAttribute('src');
|
| 90 |
-
if (!audioUrl) {
|
| 91 |
-
throw new Error('Audio URL not found');
|
| 92 |
-
}
|
| 93 |
-
|
| 94 |
-
const response = await page.context().request.get(audioUrl);
|
| 95 |
-
const audioBuffer = await response.body();
|
| 96 |
-
|
| 97 |
-
const tempDir = tmpdir();
|
| 98 |
-
const audioPath = join(tempDir, `audio_${Date.now()}.mp3`);
|
| 99 |
-
const wavPath = join(tempDir, `audio_${Date.now()}.wav`);
|
| 100 |
-
|
| 101 |
-
await fs.writeFile(audioPath, audioBuffer);
|
| 102 |
-
|
| 103 |
-
await new Promise((resolve, reject) => {
|
| 104 |
-
const ffmpeg = spawn('ffmpeg', [
|
| 105 |
-
'-i', audioPath,
|
| 106 |
-
'-ar', '16000',
|
| 107 |
-
'-ac', '1',
|
| 108 |
-
'-y',
|
| 109 |
-
wavPath
|
| 110 |
-
]);
|
| 111 |
-
|
| 112 |
-
ffmpeg.stderr.on('data', (data) => {
|
| 113 |
-
console.log('[FFmpeg]', data.toString());
|
| 114 |
-
});
|
| 115 |
-
|
| 116 |
-
ffmpeg.on('close', (code) => {
|
| 117 |
-
if (code === 0) {
|
| 118 |
-
resolve();
|
| 119 |
-
} else {
|
| 120 |
-
reject(new Error(`FFmpeg exited with code ${code}`));
|
| 121 |
-
}
|
| 122 |
-
});
|
| 123 |
-
|
| 124 |
-
ffmpeg.on('error', reject);
|
| 125 |
-
});
|
| 126 |
-
|
| 127 |
-
let Vosk;
|
| 128 |
-
try {
|
| 129 |
-
Vosk = (await import('vosk')).default;
|
| 130 |
-
} catch (err) {
|
| 131 |
-
throw new Error('Vosk module not found. Install with: npm install vosk');
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
-
const modelPath = '/app/node_modules/recaptcha-solver/model';
|
| 135 |
-
const model = new Vosk.Model(modelPath);
|
| 136 |
-
const rec = new Vosk.Recognizer({ model, sampleRate: 16000 });
|
| 137 |
-
|
| 138 |
-
const wavData = await fs.readFile(wavPath);
|
| 139 |
-
rec.acceptWaveform(wavData);
|
| 140 |
-
const result = JSON.parse(rec.finalResult());
|
| 141 |
-
|
| 142 |
-
const transcription = result.text.replace(/[^a-z ]/gi, '').trim();
|
| 143 |
-
|
| 144 |
-
console.log('[Solver] Transcription:', transcription);
|
| 145 |
-
|
| 146 |
-
const audioInput = await bframe.$('#audio-response');
|
| 147 |
-
if (!audioInput) {
|
| 148 |
-
throw new Error('Audio input not found');
|
| 149 |
-
}
|
| 150 |
-
|
| 151 |
-
await audioInput.fill(transcription);
|
| 152 |
-
await page.waitForTimeout(500);
|
| 153 |
-
|
| 154 |
-
const verifyButton = await bframe.$('#recaptcha-verify-button');
|
| 155 |
-
if (!verifyButton) {
|
| 156 |
-
throw new Error('Verify button not found');
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
await verifyButton.click();
|
| 160 |
-
await page.waitForTimeout(3000);
|
| 161 |
-
|
| 162 |
-
await fs.unlink(audioPath).catch(() => {});
|
| 163 |
-
await fs.unlink(wavPath).catch(() => {});
|
| 164 |
-
|
| 165 |
-
const solveTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 166 |
-
console.log(`[Solver] Solved in ${solveTime}s`);
|
| 167 |
-
|
| 168 |
-
return true;
|
| 169 |
-
}
|
| 170 |
-
|
| 171 |
app.get('/', (req, res) => {
|
| 172 |
res.json({
|
| 173 |
status: 'ok',
|
|
@@ -221,28 +62,10 @@ app.get('/api/solve', async (req, res) => {
|
|
| 221 |
const page = await context.newPage();
|
| 222 |
|
| 223 |
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
| 224 |
-
|
| 225 |
-
await page.waitForTimeout(5000);
|
| 226 |
|
| 227 |
-
|
| 228 |
-
return !!document.querySelector('iframe[src*="google.com/recaptcha"]');
|
| 229 |
-
});
|
| 230 |
-
|
| 231 |
-
if (!recaptchaExists) {
|
| 232 |
-
await browser.close();
|
| 233 |
-
return res.status(404).json({
|
| 234 |
-
success: false,
|
| 235 |
-
error: 'No reCAPTCHA detected',
|
| 236 |
-
message: 'The page does not contain a reCAPTCHA iframe',
|
| 237 |
-
timestamp: new Date().toISOString()
|
| 238 |
-
});
|
| 239 |
-
}
|
| 240 |
-
|
| 241 |
-
console.log('[API] reCAPTCHA detected, attempting to solve...');
|
| 242 |
|
| 243 |
-
await
|
| 244 |
-
|
| 245 |
-
await page.waitForTimeout(2000);
|
| 246 |
|
| 247 |
const solveTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 248 |
console.log(`[API] reCAPTCHA solved in ${solveTime}s`);
|
|
@@ -319,24 +142,9 @@ app.post('/api/solve', async (req, res) => {
|
|
| 319 |
|
| 320 |
const page = await context.newPage();
|
| 321 |
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
| 322 |
-
|
| 323 |
-
await page.waitForTimeout(5000);
|
| 324 |
-
|
| 325 |
-
const recaptchaExists = await page.evaluate(() => {
|
| 326 |
-
return !!document.querySelector('iframe[src*="google.com/recaptcha"]');
|
| 327 |
-
});
|
| 328 |
-
|
| 329 |
-
if (!recaptchaExists) {
|
| 330 |
-
await browser.close();
|
| 331 |
-
return res.status(404).json({
|
| 332 |
-
success: false,
|
| 333 |
-
error: 'No reCAPTCHA detected',
|
| 334 |
-
timestamp: new Date().toISOString()
|
| 335 |
-
});
|
| 336 |
-
}
|
| 337 |
|
| 338 |
console.log('[API] Attempting to solve reCAPTCHA...');
|
| 339 |
-
await
|
| 340 |
|
| 341 |
await page.waitForTimeout(2000);
|
| 342 |
|
|
|
|
| 1 |
import express from 'express';
|
| 2 |
import { chromium } from 'playwright-core';
|
| 3 |
import cors from 'cors';
|
| 4 |
+
import { solve } from './solver.js';
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
const app = express();
|
| 7 |
const PORT = process.env.PORT || 7860;
|
|
|
|
| 9 |
app.use(cors());
|
| 10 |
app.use(express.json());
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
app.get('/', (req, res) => {
|
| 13 |
res.json({
|
| 14 |
status: 'ok',
|
|
|
|
| 62 |
const page = await context.newPage();
|
| 63 |
|
| 64 |
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
|
|
|
|
|
| 65 |
|
| 66 |
+
console.log('[API] Attempting to solve reCAPTCHA...');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
+
await solve(page);
|
|
|
|
|
|
|
| 69 |
|
| 70 |
const solveTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 71 |
console.log(`[API] reCAPTCHA solved in ${solveTime}s`);
|
|
|
|
| 142 |
|
| 143 |
const page = await context.newPage();
|
| 144 |
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
console.log('[API] Attempting to solve reCAPTCHA...');
|
| 147 |
+
await solve(page);
|
| 148 |
|
| 149 |
await page.waitForTimeout(2000);
|
| 150 |
|