playwright / index.js
maylinejix's picture
Update index.js
cfe32b0 verified
import express from 'express';
import { chromium } from 'playwright-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import cors from 'cors';
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
chromium.use(StealthPlugin());
const app = express();
const PORT = process.env.PORT || 7860;
app.use(cors());
app.use(express.json({ limit: '50mb' }));
app.use('/files', express.static('public'));
const publicDir = path.join(__dirname, 'public');
await fs.mkdir(publicDir, { recursive: true }).catch(console.error);
function convertPlaywrightCode(code) {
let converted = code;
const replacements = [
[/const\s+{\s*chromium\s*}\s*=\s*require\(['"](.*?playwright.*?)['"]\)/gi, 'const chromium = globalThis.chromium'],
[/from\s+['"]playwright['"]/gi, ''],
[/import\s+{\s*chromium\s*}\s+from\s+['"]playwright['"]/gi, 'const chromium = globalThis.chromium'],
];
replacements.forEach(([pattern, replacement]) => {
converted = converted.replace(pattern, replacement);
});
return converted;
}
app.post('/api/s-playwright', async (req, res) => {
const { code, lang } = req.body;
if (!code || !lang) {
return res.status(400).json({
success: false,
error: 'Missing required fields: code and lang'
});
}
const supportedLangs = ['javascript'];
const normalizedLang = lang.toLowerCase();
if (!supportedLangs.includes(normalizedLang)) {
return res.status(400).json({
success: false,
error: `Unsupported language: "${lang}". Supported: ${supportedLangs.join(', ')}`
});
}
let browser = null;
try {
const convertedCode = convertPlaywrightCode(code);
globalThis.chromium = {
launch: async (options = {}) => {
return await chromium.launch({
headless: options.headless !== false,
args: [
'--disable-blink-features=AutomationControlled',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920,1080',
'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
...(options.args || [])
]
});
}
};
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const executableCode = new AsyncFunction('chromium', 'publicDir', 'path', 'fs', convertedCode);
const result = await executableCode(globalThis.chromium, publicDir, path, fs);
const timestamp = Date.now();
const baseUrl = `${req.protocol}://${req.get('host')}`;
const screenshotFiles = await fs.readdir(publicDir);
const recentFiles = screenshotFiles
.filter(f => f.startsWith('screenshot-') && f.endsWith('.png'))
.map(f => ({
name: f,
publicURL: `${baseUrl}/files/${f}`
}));
res.json({
success: true,
data: {
result: result,
files: recentFiles,
timestamp: timestamp
}
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
stack: error.stack
});
} finally {
if (browser) {
try {
await browser.close();
} catch (e) {
console.error('Error closing browser:', e.message);
}
}
}
});
app.get('/', (req, res) => {
res.json({
message: 'Playwright Stealth API is running',
endpoints: {
'POST /api/s-playwright': 'Execute playwright code with stealth mode'
},
features: [
'Advanced Anti-Fingerprinting',
'Stealth Plugin Enabled',
'Human-like Behavior',
'Cloudflare WAF Bypass',
'Auto Playwright code execution'
]
});
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`🚀 Playwright Stealth API running on port ${PORT}`);
console.log(`📝 Endpoint: POST /api/s-playwright`);
console.log(`🎭 Features: Anti-fingerprinting, WAF bypass, stealth mode`);
});
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully...');
process.exit(0);
});
process.on('SIGINT', async () => {
console.log('SIGINT received, shutting down gracefully...');
process.exit(0);
});