const { chromium } = require('playwright'); const express = require('express'); const archiver = require('archiver'); const { tmpdir } = require('os'); const { join } = require('path'); const { mkdirSync, rmSync } = require('fs'); const app = express(); app.use(express.json()); app.get('/run', async (req, res) => { const { url = 'https://ysmteam.io.vn/keys/free?admin=YSMTEAM®ion=Global', game = 'com.dts.freefireth' } = req.body; const ts = Date.now(); const dir = join(tmpdir(), `ysm-${ts}`); mkdirSync(dir, { recursive: true }); const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const context = await browser.newContext({ recordHar: { path: join(dir, 'traffic.har'), mode: 'full' } }); context.on('page', async p => { await p.addInitScript(() => { if (window.h) return; window.h = 1; (() => { const h = location.hostname; if (['biharkhabar.net', 'newkhabar24.com', 'insurance.odiadance.com', 'goodmorningimg.com', 'sarkarikhoj.com', 'metavise.in', 'vbnmx.online', 'property.vbnmx.online', 'earnbox.in'].includes(h)) { const i = setInterval(() => { const b = document.querySelector('center a button#tp-snp2') || [...document.querySelectorAll('center a button')].find(b => b.innerText.toUpperCase().includes('COUNTIUE')); if (b?.closest('a')?.href) { clearInterval(i); location.href = b.closest('a').href; } }, 100); } if (h === 'go.just2earn.com') { const i = setInterval(() => { const t = document.querySelector('#timer'); const b = document.querySelector('.get-link'); if (t && b && +t.innerText === 0 && !b.classList.contains('disabled')) { clearInterval(i); b.click(); } }, 300); } })(); }); }); const page = await context.newPage(); await page.goto(url, { waitUntil: 'networkidle' }); await page.selectOption('select#game', game); await page.click('button#btn_submit'); let lastPage = page; while (true) { try { const [p] = await Promise.race([ context.waitForEvent('page', { timeout: 8000 }), page.waitForTimeout(8000).then(() => null) ]); if (!p) break; lastPage = p; await lastPage.waitForLoadState('networkidle'); } catch { break; } } const html = await lastPage.content(); const css = await lastPage.evaluate(() => [...document.styleSheets].map(s => s.href ? `@import "${s.href}";` : [...s.cssRules].map(r => r.cssText).join('')).join('\n')); const js = await lastPage.evaluate(() => [...document.scripts].map(s => s.src ? `// ${s.src}` : s.textContent).join('\n\n')); const zip = archiver('zip', { zlib: { level: 9 } }); res.setHeader('Content-Type', 'application/zip'); res.setHeader('Content-Disposition', `attachment; filename="ysm-${ts}.zip"`); zip.pipe(res); zip.append(html, { name: 'index.html' }); zip.append(css, { name: 'styles.css' }); zip.append(js, { name: 'scripts.js' }); zip.finalize(); await browser.close(); res.on('finish', () => rmSync(dir, { recursive: true, force: true })); }); const PORT = process.env.PORT || 7860; app.listen(PORT, () => console.log(`API ready on ${PORT}`));