Dashme / plugins /brat.js
maylinejix's picture
Update plugins/brat.js
96039b7 verified
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
};