const express = require('express'); const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); const Tesseract = require('tesseract.js'); const sharp = require('sharp'); const crypto = require('crypto'); puppeteer.use(StealthPlugin()); const app = express(); const port = process.env.PORT || 7860; // Fungsi pikeun nyieun sidik jari gambar (Hashing) async function getImageHash(buffer) { try { const processed = await sharp(buffer) .grayscale() .resize(32, 32, { fit: 'fill' }) .threshold(120) .toBuffer(); return crypto.createHash('md5').update(processed).digest('hex'); } catch (e) { return null; } } // Fungsi Pre-processing khusus OCR async function preprocessForOCR(buffer) { return await sharp(buffer) .grayscale() .threshold(120) .resize(400) // Gedean meh leuwih jelas dibaca .toBuffer(); } app.get('/solve', async (req, res) => { const targetUrl = req.query.url; if (!targetUrl) return res.status(400).send({ error: "URL-na mana?" }); // ARGUMEN PENTING: Meh Hugging Face teu 503/Crash const browser = await puppeteer.launch({ headless: "new", args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--no-zygote', '--single-process', '--hide-scrollbars' ] }); try { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); console.log(`Maju ka: ${targetUrl}`); await page.goto(targetUrl, { waitUntil: 'networkidle2', timeout: 60000 }); // Tunggu antibot links aya dina DOM await page.waitForSelector('.antibotlinks', { timeout: 15000 }); // 1. Baca Instruksi Utama const instructionImg = await page.$('#atb-instruction img'); let instrBuffer = await instructionImg.screenshot(); instrBuffer = await preprocessForOCR(instrBuffer); const { data: { text: rawInstruction } } = await Tesseract.recognize(instrBuffer, 'eng'); const order = rawInstruction.toLowerCase() .replace(/[^a-z0-9, ]/g, '') .split(/[, ]+/) .filter(t => t.length > 0); console.log("Urutan nu dideteksi:", order); // 2. Scan & Map kabeh link antibot const links = await page.$$('.antibotlinks a'); let linkMap = []; for (const link of links) { const img = await link.$('img'); const imgBuffer = await img.screenshot(); const cleanImg = await preprocessForOCR(imgBuffer); const { data: { text: label } } = await Tesseract.recognize(cleanImg, 'eng'); linkMap.push({ element: link, label: label.toLowerCase().replace(/[^a-z0-9]/g, ''), done: false }); } // 3. Eksekusi Klik dumasar urutan let clickedItems = []; for (const target of order) { const match = linkMap.find(item => (item.label.includes(target) || target.includes(item.label)) && !item.done ); if (match) { console.log(`KLIK: ${match.label} (Target: ${target})`); await match.element.click(); match.done = true; clickedItems.push(target); await new Promise(r => setTimeout(r, 1500)); } } res.send({ status: clickedItems.length === order.length ? "Success" : "Partial", order: order, clicked: clickedItems }); } catch (err) { console.error("Fatal Error:", err.message); res.status(500).send({ error: err.message }); } finally { // IEU PENTING: Meh RAM teu bocor sarta teu 503 await browser.close(); } }); app.listen(port, () => console.log(`DAN Solver Engine up on port ${port}`));