Pastebin
Retrouvez, créez et partagez vos snippets en temps réel.
Rechercher un Pastebin
Aucun paste trouvé.
Créer un paste
Pastebin
Blog
test4
const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); const path = require('path'); const fs = require('fs'); // ⚠️ REPLACE WITH YOUR API KEY const CAPTCHA_API_KEY = 'f1fc51f083043b2c22c7835ffe7a8721'; // Configuration const CONFIG = { // --- NEW TOGGLE --- ENABLE_CAPTCHA_SOLVER: false, // Set to false to deactivate all captcha detection and solving CAPTCHA_SERVICE: '2captcha', // '2captcha' or 'capsolver' USE_PROXY: true, PROXY_SERVER: 'http://geo.g-w.info:10080', PROXY_USERNAME: 'user-FUBJvHtbDOaVNm3M-type-mobile-country-FR', PROXY_PASSWORD: '1PRX9EnYq8WtCFy0', // Extensions paths EXTENSION_1_PATH: path.join(process.env.HOME, 'Downloads', 'csgoroll-auto-claim'), EXTENSION_2_PATH: path.join(process.env.HOME, 'Downloads', 'capmonster'), USE_USER_DATA_DIR: false, USER_DATA_DIR: path.resolve(__dirname, 'chrome-profile'), // Target URL TARGET_URL: 'https://www.csgoroll.com/', // CAPTCHA settings CHECK_INTERVAL: 7000, SOLVE_INVISIBLE: false, MAX_SOLVE_ATTEMPTS: 60, POLL_DELAY: 3000, // Discord Webhook DISCORD_WEBHOOK_URL: 'YOUR_DISCORD_WEBHOOK_URL_HERE', // Replace with your webhook URL // Memory Monitor settings ENABLE_MEMORY_MONITOR: true, MEMORY_CHECK_INTERVAL: 5000, // Check every 5 seconds // Error detection settings CHECK_ERROR_PAGES: true, // Check for HTTP error codes and Chrome error pages AUTO_RETRY_ON_ERROR: true, // Automatically retry/refresh when error page is detected RETRY_DELAY: 5000, // Wait 5 seconds before retrying (in milliseconds) MAX_RETRY_ATTEMPTS: 10, // Maximum number of retry attempts (0 = infinite) }; // Apply stealth plugin puppeteer.use(StealthPlugin()); // ==================== MEMORY MONITOR ==================== function formatBytes(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function getMemoryUsage() { const usage = process.memoryUsage(); return { rss: usage.rss, // Resident Set Size - total memory allocated heapTotal: usage.heapTotal, // Total heap size heapUsed: usage.heapUsed, // Actual heap used external: usage.external, // External memory (buffers, etc) }; } function displayMemoryStats() { const usage = getMemoryUsage(); const totalMem = require('os').totalmem(); const freeMem = require('os').freemem(); const usedSystemMem = totalMem - freeMem; const percentUsed = ((usedSystemMem / totalMem) * 100).toFixed(1); console.log('\n📊 ═══════════════ MEMORY STATS ═══════════════'); console.log(`🔹 Process RSS: ${formatBytes(usage.rss)}`); console.log(`🔹 Heap Used: ${formatBytes(usage.heapUsed)} / ${formatBytes(usage.heapTotal)}`); console.log(`🔹 External: ${formatBytes(usage.external)}`); console.log(`🔹 System Total: ${formatBytes(totalMem)}`); console.log(`🔹 System Free: ${formatBytes(freeMem)}`); console.log(`🔹 System Used: ${formatBytes(usedSystemMem)} (${percentUsed}%)`); console.log('═════════════════════════════════════════════\n'); } let memoryMonitorInterval = null; function startMemoryMonitor() { if (!CONFIG.ENABLE_MEMORY_MONITOR) return; console.log('🧠 Memory monitor started...\n'); displayMemoryStats(); memoryMonitorInterval = setInterval(() => { displayMemoryStats(); }, CONFIG.MEMORY_CHECK_INTERVAL); } function stopMemoryMonitor() { if (memoryMonitorInterval) { clearInterval(memoryMonitorInterval); console.log('🛑 Memory monitor stopped.'); } } // ==================== ERROR PAGE DETECTION ==================== async function checkForErrorPage(page, response = null) { if (!CONFIG.CHECK_ERROR_PAGES) return null; try { let errorInfo = null; // Check response status (404, 500, etc.) if (response && !response.ok()) { const status = response.status(); errorInfo = { type: 'HTTP_ERROR', status: status, statusText: response.statusText(), url: response.url(), title: await page.title().catch(() => 'Unable to get title'), }; } // Check for Chrome error pages const url = await page.url(); const title = await page.title().catch(() => ''); if (url.startsWith('chrome-error://') || url.startsWith('data:text/html,chromewebdata') || title.toLowerCase().includes("this site can't be reached") || title.toLowerCase().includes('connection timed out') || title.toLowerCase().includes('unable to connect')) { // Get error details from the page const chromeErrorDetails = await page.evaluate(() => { const errorCode = document.querySelector('#error-code'); const mainMessage = document.querySelector('#main-message'); const suggestions = document.querySelector('#suggestions-list'); return { errorCode: errorCode ? errorCode.textContent : '', mainMessage: mainMessage ? mainMessage.textContent : '', suggestions: suggestions ? suggestions.textContent : '', bodyText: document.body.innerText.substring(0, 1000) }; }).catch(() => null); errorInfo = { type: 'CHROME_ERROR', url: url, title: title, details: chromeErrorDetails, }; } // Check for common HTTP error pages (404, 500, etc.) in page content if (!errorInfo) { const pageContent = await page.evaluate(() => { const title = document.title.toLowerCase(); const bodyText = document.body.innerText.toLowerCase(); const errorPatterns = [ '404', '403', '500', '502', '503', 'not found', 'access denied', 'forbidden', 'service unavailable', 'bad gateway', 'internal server error' ]; const foundError = errorPatterns.find(pattern => title.includes(pattern) || bodyText.includes(pattern) ); if (foundError) { return { detected: true, pattern: foundError, title: document.title, snippet: document.body.innerText.substring(0, 500) }; } return { detected: false }; }).catch(() => ({ detected: false })); if (pageContent.detected) { errorInfo = { type: 'PAGE_ERROR', url: await page.url(), title: pageContent.title, errorPattern: pageContent.pattern, snippet: pageContent.snippet, }; } } return errorInfo; } catch (e) { console.error('❌ Error detection failed:', e.message); return null; } } // ==================== DISCORD WEBHOOK ==================== async function sendDiscordWebhook(errorInfo, screenshotPath = null) { if (!CONFIG.DISCORD_WEBHOOK_URL || CONFIG.DISCORD_WEBHOOK_URL === 'YOUR_DISCORD_WEBHOOK_URL_HERE') { console.log('⚠️ Discord webhook not configured. Skipping notification.'); return; } try { let description = ''; let errorTitle = '🚨 Error Page Detected'; switch (errorInfo.type) { case 'HTTP_ERROR': errorTitle = `🚨 HTTP ${errorInfo.status} Error`; description = `**Status:** ${errorInfo.status} ${errorInfo.statusText}`; break; case 'CHROME_ERROR': errorTitle = '🚨 Chrome Navigation Error'; if (errorInfo.details) { description = `**Error Code:** ${errorInfo.details.errorCode}\n**Message:** ${errorInfo.details.mainMessage}`; } break; case 'PAGE_ERROR': errorTitle = `🚨 Page Error (${errorInfo.errorPattern})`; description = errorInfo.snippet ? errorInfo.snippet.substring(0, 1000) : ''; break; case 'NAVIGATION_TIMEOUT': errorTitle = '🚨 Navigation Timeout'; description = `Navigation to URL exceeded timeout limit.`; break; case 'NAVIGATION_FAILED': errorTitle = '🚨 Navigation Failed'; description = errorInfo.error || 'Unknown navigation error'; break; } const embed = { title: errorTitle, color: 0xFF0000, // Red color description: description, fields: [ { name: '🔗 URL', value: errorInfo.url || 'N/A', inline: false }, { name: '📄 Page Title', value: errorInfo.title || 'N/A', inline: false }, { name: '🕒 Timestamp', value: new Date().toLocaleString(), inline: false } ], footer: { text: 'Puppeteer Error Monitor' } }; const payload = { username: 'Error Monitor Bot', embeds: [embed] }; // If screenshot exists, send it as a file if (screenshotPath && fs.existsSync(screenshotPath)) { const FormData = require('form-data'); const form = new FormData(); form.append('payload_json', JSON.stringify(payload)); form.append('file', fs.createReadStream(screenshotPath)); const response = await fetch(CONFIG.DISCORD_WEBHOOK_URL, { method: 'POST', body: form, headers: form.getHeaders() }); if (response.ok) { console.log('✅ Discord notification sent with screenshot!'); } else { console.error('❌ Discord webhook failed:', await response.text()); } } else { // Send without screenshot const response = await fetch(CONFIG.DISCORD_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.ok) { console.log('✅ Discord notification sent!'); } else { console.error('❌ Discord webhook failed:', await response.text()); } } } catch (error) { console.error('❌ Discord webhook error:', error.message); } } // ==================== ERROR PAGE HANDLER ==================== async function handleErrorPage(page, errorInfo, autoRetry = false) { if (!errorInfo) return false; console.log('\n🚨 ═══════════ ERROR DETECTED ═══════════'); console.log(`📋 Type: ${errorInfo.type}`); if (errorInfo.status) console.log(`📊 Status: ${errorInfo.status} ${errorInfo.statusText}`); console.log('🔗 URL:', errorInfo.url); console.log('📄 Title:', errorInfo.title); console.log('═════════════════════════════════════════════\n'); // Take screenshot const screenshotPath = path.join(__dirname, `error_${Date.now()}.png`); try { await page.screenshot({ path: screenshotPath, fullPage: true }); console.log(`📸 Screenshot saved: ${screenshotPath}`); // Send to Discord await sendDiscordWebhook(errorInfo, screenshotPath); // Optional: delete screenshot after sending // fs.unlinkSync(screenshotPath); } catch (e) { console.error('❌ Screenshot failed:', e.message); await sendDiscordWebhook(errorInfo); } return true; } // ==================== 2CAPTCHA API ==================== async function solve2Captcha(sitekey, url, isInvisible = false) { try { console.log(`📤 Sending ${isInvisible ? 'invisible ' : ''}CAPTCHA to 2Captcha...`); const params = new URLSearchParams({ key: CAPTCHA_API_KEY, method: 'userrecaptcha', googlekey: sitekey, pageurl: url, invisible: isInvisible ? 1 : 0, json: 1 }); const submitResponse = await fetch('https://2captcha.com/in.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString() }); const submitData = await submitResponse.json(); if (submitData.status !== 1) { throw new Error(`2Captcha submit error: ${submitData.request}`); } const captchaId = submitData.request; console.log(`⏳ Captcha ID: ${captchaId} - waiting for solution...`); const startTime = Date.now(); for (let i = 0; i < CONFIG.MAX_SOLVE_ATTEMPTS; i++) { await new Promise(resolve => setTimeout(resolve, CONFIG.POLL_DELAY)); const resultResponse = await fetch( `https://2captcha.com/res.php?key=${CAPTCHA_API_KEY}&action=get&id=${captchaId}&json=1` ); const resultData = await resultResponse.json(); if (resultData.status === 1) { const duration = ((Date.now() - startTime) / 1000).toFixed(1); console.log(`✅ 2Captcha solved in ${duration}s`); return resultData.request; } else if (resultData.request === 'CAPCHA_NOT_READY') { continue; } else { throw new Error(`2Captcha error: ${resultData.request}`); } } throw new Error('2Captcha timeout'); } catch (error) { console.error('❌ 2Captcha error:', error.message); return null; } } // ==================== CAPSOLVER API ==================== async function solveCapSolver(sitekey, url, isInvisible = false) { try { console.log(`📤 Sending ${isInvisible ? 'invisible ' : ''}CAPTCHA to CapSolver...`); const createResponse = await fetch('https://api.capsolver.com/createTask', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ clientKey: CAPTCHA_API_KEY, task: { type: 'ReCaptchaV2TaskProxyless', websiteURL: url, websiteKey: sitekey, isInvisible: isInvisible } }) }); const createData = await createResponse.json(); if (createData.errorId !== 0) { throw new Error(`CapSolver error: ${createData.errorDescription || createData.errorCode}`); } const taskId = createData.taskId; console.log(`⏳ Task ID: ${taskId} - waiting for solution...`); const startTime = Date.now(); for (let i = 0; i < CONFIG.MAX_SOLVE_ATTEMPTS; i++) { await new Promise(resolve => setTimeout(resolve, CONFIG.POLL_DELAY)); const resultResponse = await fetch('https://api.capsolver.com/getTaskResult', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ clientKey: CAPTCHA_API_KEY, taskId: taskId }) }); const resultData = await resultResponse.json(); if (resultData.errorId !== 0) { throw new Error(`CapSolver error: ${resultData.errorDescription || resultData.errorCode}`); } if (resultData.status === 'ready') { const duration = ((Date.now() - startTime) / 1000).toFixed(1); console.log(`✅ CapSolver solved in ${duration}s`); return resultData.solution.gRecaptchaResponse; } else if (resultData.status === 'failed') { throw new Error('CapSolver failed to solve'); } } throw new Error('CapSolver timeout'); } catch (error) { console.error('❌ CapSolver error:', error.message); return null; } } // ==================== UNIFIED SOLVER ==================== async function solveCaptcha(sitekey, url, isInvisible = false) { if (CONFIG.CAPTCHA_SERVICE === '2captcha') { return await solve2Captcha(sitekey, url, isInvisible); } else if (CONFIG.CAPTCHA_SERVICE === 'capsolver') { return await solveCapSolver(sitekey, url, isInvisible); } else { throw new Error('Invalid CAPTCHA_SERVICE configured'); } } // ==================== CAPTCHA DETECTION ==================== async function detectCaptchas(page) { return await page.evaluate(() => { const captchas = []; const iframes = document.querySelectorAll('iframe[src*="recaptcha"]'); iframes.forEach(iframe => { const src = iframe.getAttribute('src'); if (!src) return; const match = src.match(/[?&]k=([^&]+)/); if (match && match[1]) { const sitekey = match[1]; const isInvisible = src.includes('size=invisible'); let container = iframe.closest('.grecaptcha-badge') || iframe.closest('[data-recaptcha-action]') || iframe.closest('#recaptcha-target') || iframe.parentElement; if (!container.hasAttribute('data-solver-processed')) { captchas.push({ sitekey: sitekey, url: window.location.href, invisible: isInvisible, processed: false }); container.setAttribute('data-solver-processed', 'true'); } } }); return captchas; }); } // ==================== CAPTCHA INJECTION ==================== async function injectCaptchaSolution(page, token) { console.log('💉 Injecting token into page...'); return await page.evaluate((token) => { document.querySelectorAll('[name="g-recaptcha-response"], #g-recaptcha-response, .g-recaptcha-response').forEach(el => { el.value = token; el.innerHTML = token; el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); }); if (window.grecaptcha) { window.grecaptcha.getResponse = () => token; } let callbackTriggered = false; if (window.___grecaptcha_cfg && window.___grecaptcha_cfg.clients) { const clients = window.___grecaptcha_cfg.clients; Object.keys(clients).forEach(clientId => { const client = clients[clientId]; function findAndExecute(obj, depth = 0) { if (depth > 5 || !obj) return; for (const key in obj) { try { const target = obj[key]; if (target && typeof target === 'object' && target.callback) { const cb = target.callback; if (typeof cb === 'function') { cb(token); callbackTriggered = true; } else if (typeof window[cb] === 'function') { window[cb](token); callbackTriggered = true; } } else if (typeof target === 'object') { findAndExecute(target, depth + 1); } } catch(e) {} } } findAndExecute(client); }); } const captchaContainers = document.querySelectorAll('.g-recaptcha, [data-recaptcha-action]'); captchaContainers.forEach(container => { const callbackName = container.getAttribute('data-callback') || container.getAttribute('data-recaptcha-action'); if (callbackName && typeof window[callbackName] === 'function') { window[callbackName](token); callbackTriggered = true; } }); return callbackTriggered; }, token); } // ==================== AUTO-CLICK SUBMIT ==================== async function attemptSubmit(page) { console.log('🎯 Attempting to find and click submit button...'); try { await page.evaluate(() => { const submitBtn = document.querySelector('button[type="submit"]') || document.querySelector('#recaptcha-demo-submit') || Array.from(document.querySelectorAll('button')).find(b => b.textContent.toLowerCase().includes('join') || b.textContent.toLowerCase().includes('verify') || b.textContent.toLowerCase().includes('submit') ); if (submitBtn) { console.log('✅ Found submit button:', submitBtn.textContent.trim()); submitBtn.click(); return true; } return false; }); } catch (e) { console.error('❌ Submit attempt failed:', e.message); } } // ==================== MAIN SOLVER ==================== async function solveCaptchaIfPresent(page, solvedSitekeys) { // Exit immediately if solver is deactivated in CONFIG if (!CONFIG.ENABLE_CAPTCHA_SOLVER) return false; try { const captchas = await detectCaptchas(page); if (captchas.length === 0) return false; for (const captcha of captchas) { if (solvedSitekeys.has(captcha.sitekey)) continue; if (captcha.invisible && !CONFIG.SOLVE_INVISIBLE) { console.log('⏭️ Skipping invisible captcha based on config.'); continue; } console.log(`🔍 New ${captcha.invisible ? 'invisible ' : ''}CAPTCHA detected!`); const token = await solveCaptcha(captcha.sitekey, captcha.url, captcha.invisible); if (token) { await injectCaptchaSolution(page, token); console.log('✅ Token injected successfully.'); solvedSitekeys.add(captcha.sitekey); await new Promise(resolve => setTimeout(resolve, 1000)); await attemptSubmit(page); return true; } } return false; } catch (e) { console.error('❌ Solve attempt failed:', e.message); return false; } } // ==================== EXTENSION VALIDATION ==================== function validateExtension(extensionPath, extensionName) { if (!fs.existsSync(extensionPath)) return false; const manifestPath = path.join(extensionPath, 'manifest.json'); if (!fs.existsSync(manifestPath)) return false; return true; } // ==================== NAVIGATION WITH ERROR HANDLING ==================== async function navigateWithErrorDetection(page, url, options = {}) { let response = null; let errorInfo = null; try { console.log('🌐 Navigating to:', url); response = await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000, ...options }); // Check if navigation succeeded but returned error status if (response && !response.ok()) { errorInfo = await checkForErrorPage(page, response); } else { // Check for Chrome error pages even if response is "ok" errorInfo = await checkForErrorPage(page); } } catch (error) { console.error('❌ Navigation failed:', error.message); // Navigation threw an error (timeout, network error, etc.) if (error.message.includes('Timeout')) { errorInfo = { type: 'NAVIGATION_TIMEOUT', url: url, title: await page.title().catch(() => 'Unable to get title'), error: error.message }; } else { errorInfo = { type: 'NAVIGATION_FAILED', url: url, title: await page.title().catch(() => 'Unable to get title'), error: error.message }; } // Check if Chrome error page was loaded const chromeError = await checkForErrorPage(page); if (chromeError) { errorInfo = chromeError; } } // Handle any detected errors if (errorInfo) { await handleErrorPage(page, errorInfo); } return { response, errorInfo }; } // ==================== AUTO-RETRY NAVIGATION ==================== async function navigateWithRetry(page, url, options = {}) { let attemptCount = 0; const maxAttempts = CONFIG.MAX_RETRY_ATTEMPTS || Infinity; while (attemptCount < maxAttempts) { attemptCount++; if (attemptCount > 1) { console.log(`\n🔄 Retry attempt ${attemptCount}/${maxAttempts === Infinity ? '∞' : maxAttempts}...`); console.log(`⏳ Waiting ${CONFIG.RETRY_DELAY / 1000}s before retry...\n`); await new Promise(resolve => setTimeout(resolve, CONFIG.RETRY_DELAY)); } const { response, errorInfo } = await navigateWithErrorDetection(page, url, options); // If no error, we successfully loaded the page if (!errorInfo) { if (attemptCount > 1) { console.log(`✅ Successfully loaded page after ${attemptCount} attempts!\n`); } return { response, errorInfo: null, attempts: attemptCount }; } // If auto-retry is disabled, return immediately if (!CONFIG.AUTO_RETRY_ON_ERROR) { return { response, errorInfo, attempts: attemptCount }; } // Error detected and auto-retry is enabled, continue loop console.log(`⚠️ Error detected. ${maxAttempts === Infinity ? 'Retrying...' : `Will retry (${maxAttempts - attemptCount} attempts remaining)...`}`); } // Max attempts reached console.log(`\n❌ Max retry attempts (${maxAttempts}) reached. Giving up.\n`); return { response: null, errorInfo: { type: 'MAX_RETRIES_EXCEEDED', url }, attempts: attemptCount }; } // ==================== MAIN FUNCTION ==================== (async () => { console.log('🚀 Starting Enhanced Puppeteer CAPTCHA Solver...'); console.log(`🛡️ Solver Status: ${CONFIG.ENABLE_CAPTCHA_SOLVER ? 'ACTIVE ✅' : 'DEACTIVATED ❌'}`); console.log(`🧠 Memory Monitor: ${CONFIG.ENABLE_MEMORY_MONITOR ? 'ACTIVE ✅' : 'DEACTIVATED ❌'}`); console.log(`🚨 Error Detection: ${CONFIG.CHECK_ERROR_PAGES ? 'ACTIVE ✅' : 'DEACTIVATED ❌'}`); console.log(`🔄 Auto-Retry: ${CONFIG.AUTO_RETRY_ON_ERROR ? 'ACTIVE ✅' : 'DEACTIVATED ❌'}`); if (CONFIG.AUTO_RETRY_ON_ERROR) { console.log(` └─ Max Attempts: ${CONFIG.MAX_RETRY_ATTEMPTS || '∞'} | Retry Delay: ${CONFIG.RETRY_DELAY / 1000}s\n`); } // Start memory monitor startMemoryMonitor(); let extensionsToLoad = []; if (!CONFIG.USE_USER_DATA_DIR) { if (validateExtension(CONFIG.EXTENSION_1_PATH, 'Extension 1')) extensionsToLoad.push(CONFIG.EXTENSION_1_PATH); if (validateExtension(CONFIG.EXTENSION_2_PATH, 'Extension 2')) extensionsToLoad.push(CONFIG.EXTENSION_2_PATH); } const launchArgs = [ '--no-sandbox', '--disable-setuid-sandbox', '--start-maximized', '--window-size=1920,1080', '--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage', '--ignore-certificate-errors', ]; if (CONFIG.USE_PROXY) launchArgs.unshift(`--proxy-server=${CONFIG.PROXY_SERVER}`); const launchOptions = { headless: false, executablePath: '/usr/bin/google-chrome', args: launchArgs, defaultViewport: null, }; if (extensionsToLoad.length > 0 && !CONFIG.USE_USER_DATA_DIR) { launchOptions.pipe = true; launchOptions.enableExtensions = extensionsToLoad; } else if (CONFIG.USE_USER_DATA_DIR) { if (!fs.existsSync(CONFIG.USER_DATA_DIR)) fs.mkdirSync(CONFIG.USER_DATA_DIR, { recursive: true }); launchArgs.push(`--user-data-dir=${CONFIG.USER_DATA_DIR}`); } const browser = await puppeteer.launch(launchOptions); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); if (CONFIG.USE_PROXY) { await page.authenticate({ username: CONFIG.PROXY_USERNAME, password: CONFIG.PROXY_PASSWORD }); } const solvedSitekeys = new Set(); // Combined monitoring interval for captcha and periodic error checks const monitoringInterval = setInterval(async () => { if (CONFIG.ENABLE_CAPTCHA_SOLVER) { await solveCaptchaIfPresent(page, solvedSitekeys); } // Periodic check for errors (in case page changes) if (CONFIG.CHECK_ERROR_PAGES && CONFIG.AUTO_RETRY_ON_ERROR) { const errorInfo = await checkForErrorPage(page); if (errorInfo) { await handleErrorPage(page, errorInfo); // Auto-refresh if error detected during monitoring console.log('🔄 Error detected during monitoring. Refreshing page...'); await new Promise(resolve => setTimeout(resolve, CONFIG.RETRY_DELAY)); try { await page.reload({ waitUntil: 'networkidle2', timeout: 30000 }); // Check if refresh fixed the issue const recheckError = await checkForErrorPage(page); if (!recheckError) { console.log('✅ Page refresh successful! Error cleared.'); } } catch (e) { console.error('❌ Page refresh failed:', e.message); } } } }, CONFIG.CHECK_INTERVAL); // Navigate with auto-retry const { response, errorInfo, attempts } = await navigateWithRetry(page, CONFIG.TARGET_URL); if (!errorInfo) { await new Promise(resolve => setTimeout(resolve, 2000)); if (CONFIG.ENABLE_CAPTCHA_SOLVER) { await solveCaptchaIfPresent(page, solvedSitekeys); } } console.log(`\n✅ Monitoring active. Browser open.\n`); // Graceful shutdown handler process.on('SIGINT', () => { console.log('\n🛑 Shutting down...'); stopMemoryMonitor(); clearInterval(monitoringInterval); browser.close(); process.exit(0); }); await new Promise(() => {}); })().catch(err => { console.error('💥 Fatal error:', err); stopMemoryMonitor(); process.exit(1); });
Créé il y a 2 semaines.