File size: 4,175 Bytes
5c59e1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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}`));