const puppeteer = require('puppeteer'); const axios = require('axios'); const Jimp = require('jimp'); const FormData = require('form-data'); const UPLOAD_API = 'https://cdnme.idnet.my.id/upload'; const devicesMap = { iphone17: { userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1', viewport: { width: 402, height: 874, deviceScaleFactor: 3, isMobile: true, hasTouch: true } } }; async function generateBrat(text) { const device = devicesMap.iphone17; const browser = await puppeteer.launch({ headless: 'new', executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium', args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--disable-gpu', '--font-render-hinting=none', '--force-color-profile=srgb', '--disable-web-security' ] }); try { const page = await browser.newPage(); await page.setViewport(device.viewport); await page.setUserAgent(device.userAgent); await page.evaluateOnNewDocument(() => { Object.defineProperty(navigator, 'platform', { get: () => 'iPhone' }); }); await page.goto('https://www.bratgenerator.com/', { waitUntil: 'networkidle2', timeout: 60000 }); await page.addStyleTag({ content: ` * { font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif !important; } body, input, textarea, canvas { font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif !important; } ` }); await page.waitForSelector('#textInput', { timeout: 30000 }); const whiteButton = await page.$('#toggleButtonWhite'); if (whiteButton) { await page.click('#toggleButtonWhite'); await new Promise(resolve => setTimeout(resolve, 500)); } await page.evaluate((txt) => { const input = document.getElementById('textInput'); input.value = txt; input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); }, text); await new Promise(resolve => setTimeout(resolve, 2000)); const canvas = await page.$('canvas'); if (canvas) { const screenshot = await canvas.screenshot({ type: 'png', encoding: 'base64' }); await browser.close(); return screenshot; } const screenshot = await page.screenshot({ type: 'png', encoding: 'base64', fullPage: false }); await browser.close(); return screenshot; } catch (error) { await browser.close(); throw error; } } async function processImage(base64Data) { const imageBuffer = Buffer.from(base64Data, 'base64'); const image = await Jimp.read(imageBuffer); const width = image.getWidth(); const height = image.getHeight(); const size = Math.min(width, height); const x = Math.floor((width - size) / 2); const y = Math.floor((height - size) / 2); image.crop(x, y, size, size); image.resize(1080, 1080); return await image.getBufferAsync(Jimp.MIME_PNG); } async function uploadImage(imageBuffer) { const form = new FormData(); form.append('file', imageBuffer, { filename: `brat-${Date.now()}.png`, contentType: 'image/png' }); const response = await axios.post(UPLOAD_API, form, { headers: form.getHeaders(), timeout: 30000 }); if (!response.data.success) { throw new Error('Failed to upload image'); } return response.data.url; } const handler = async (req, res) => { try { const { text } = req.query; if (!text) { return res.status(400).json({ success: false, error: 'Missing required parameter: text' }); } const base64Screenshot = await generateBrat(text); const processedImage = await processImage(base64Screenshot); const imageUrl = await uploadImage(processedImage); return res.json({ author: "Herza", success: true, data: { text: text, url: imageUrl, size: "1080x1080", } }); } catch (error) { console.error('Error:', error); return res.status(500).json({ success: false, error: error.message, timestamp: new Date().toISOString() }); } }; module.exports = { name: 'Brat Generator', description: 'Generate brat style images with custom text and Apple emoji', type: 'GET', routes: ['api/maker/brat'], tags: ['maker'], parameters: ['text'], limit: null, enabled: true, main: ['Maker'], handler };