const fs = require('fs'); const path = require('path'); const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); puppeteer.use(StealthPlugin()); const { loadConfig, loadSitesFromFile } = require('./src/config'); const { processSite } = require('./src/processor'); const { createCLI, parseCLI } = require('./src/cli'); async function main() { const cliOptions = parseCLI(); if (cliOptions.help) { createCLI().help(); return; } const config = loadConfig(); let sitesToProcess = config.sites || []; if (cliOptions.file) { console.log(`Loading sites from: ${cliOptions.file}`); sitesToProcess = loadSitesFromFile(cliOptions.file); console.log(`Loaded ${sitesToProcess.length} sites from file`); } const logFile = cliOptions.log ? path.join(__dirname, `run_${new Date().toISOString().replace(/[:.]/g, '-')}.log`) : null; if (cliOptions.target) { sitesToProcess = sitesToProcess.filter(site => site.name.toLowerCase().includes(cliOptions.target.toLowerCase()) || site.url.toLowerCase().includes(cliOptions.target.toLowerCase()) ); if (sitesToProcess.length === 0) { console.error(`No site found matching "${cliOptions.target}"`); return; } console.log(`Targeting ${sitesToProcess.length} site(s)`); } if (cliOptions.keepOpen) { console.log('Keep-open mode: Tabs will stay open for verification'); } const browserConfig = config.browser || {}; const globalCreds = config.global_credentials || {}; const userDataDir = browserConfig.userDataDir; if (!userDataDir) { console.error('userDataDir not set in config.toml'); return; } if (cliOptions.log && logFile) { const originalLog = console.log; const originalError = console.error; const originalWarn = console.warn; const writeToLog = (type, args) => { const message = args.map(arg => typeof arg === 'string' ? arg : JSON.stringify(arg)).join(' '); fs.appendFileSync(logFile, `[${new Date().toISOString()}] [${type}] ${message}\n`); }; console.log = (...args) => { writeToLog('LOG', args); originalLog.apply(console, args); }; console.error = (...args) => { writeToLog('ERROR', args); originalError.apply(console, args); }; console.warn = (...args) => { writeToLog('WARN', args); originalWarn.apply(console, args); }; console.log(`Logging to: ${logFile}`); } const failedSites = []; const processedCount = { success: 0, failed: 0 }; const browser = await puppeteer.launch({ headless: false, userDataDir: userDataDir, args: ['--start-maximized', '--no-sandbox', '--disable-setuid-sandbox'] }); try { console.log(`\nProcessing ${sitesToProcess.length} sites...\n`); for (let i = 0; i < sitesToProcess.length; i++) { const site = sitesToProcess[i]; console.log(`[${i + 1}/${sitesToProcess.length}]`); const result = await processSite(browser, site, globalCreds, browserConfig, cliOptions.keepOpen, cliOptions.dryRun); if (result.siteFailed) { failedSites.push({ name: site.name, url: site.url, reason: result.failureReason, timestamp: new Date().toISOString() }); processedCount.failed++; } else { processedCount.success++; } await new Promise(r => setTimeout(r, 1000)); } console.log(`\n${'='.repeat(70)}`); console.log(`Done: ${processedCount.success} success, ${processedCount.failed} failed`); } catch(error) { console.error('Fatal error:', error.message); } finally { if (cliOptions.keepOpen) { console.log(`\nBrowser kept open for verification`); console.log(` Close browser manually when done`); } else { await browser.close(); } if (failedSites.length > 0) { const reportPath = path.join(__dirname, 'failed_sites.txt'); const now = new Date(); const dateStr = now.toLocaleDateString('en-GB'); const timeStr = now.toLocaleTimeString('en-GB'); let reportContent = ''; if (!fs.existsSync(reportPath)) { reportContent = 'DATE | TIME | WEBSITE | REASON\n'; reportContent += '-'.repeat(100) + '\n'; } for (const site of failedSites) { const website = `${site.name} (${site.url})`.substring(0, 32).padEnd(32); reportContent += `${dateStr} | ${timeStr} | ${website} | ${site.reason}\n`; } fs.appendFileSync(reportPath, reportContent); console.log(`${failedSites.length} failed. See: failed_sites.txt`); } } } main();