| 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}`)); | |