brat / app2.js
andhikagg's picture
Update app2.js
bb24c41 verified
const express = require('express');
const { chromium, devices } = require('playwright');
const cors = require('cors');
const dotenv = require('dotenv');
const os = require('os');
dotenv.config();
const config = {
maxTextLength: 100,
defaultViewport: { width: 1920, height: 1080 },
iPhoneViewport: { width: 390, height: 844 }
};
let defaultBrowser, defaultPage, iPhoneBrowser, iPhonePage;
const utils = {
async initialize() {
if (!defaultBrowser) {
defaultBrowser = await chromium.launch({ headless: true });
const context = await defaultBrowser.newContext({
viewport: config.defaultViewport
});
defaultPage = await context.newPage();
await defaultPage.goto('https://www.bratgenerator.com/', {
waitUntil: 'networkidle'
});
try {
await defaultPage.click('#onetrust-accept-btn-handler', { timeout: 2000 });
} catch {}
await defaultPage.evaluate(() => setupTheme('white'));
}
},
async generateBrat(text) {
await defaultPage.fill('#textInput', text);
await defaultPage.waitForTimeout(500);
const overlay = defaultPage.locator('#textOverlay');
return overlay.screenshot({ timeout: 5000 });
},
async close() {
if (defaultBrowser) await defaultBrowser.close();
}
};
const utils2 = {
async initialize() {
if (!iPhoneBrowser) {
iPhoneBrowser = await chromium.launch({ headless: true });
// Buat context dengan konfigurasi iPhone yang spesifik
const context = await iPhoneBrowser.newContext({
...devices['iPhone 13 Pro'],
locale: 'en-US',
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
colorScheme: 'light',
forcedColors: 'none',
viewport: config.iPhoneViewport,
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1'
});
iPhonePage = await context.newPage();
// Inject necessary meta tags and CSS
await iPhonePage.route('**/*', async route => {
if (route.request().resourceType() === 'document') {
const response = await route.fetch();
const text = await response.text();
const modifiedHtml = text.replace('</head>',
`<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
@font-face {
font-family: 'Apple Color Emoji';
src: local('Apple Color Emoji');
unicode-range: U+1F300-1F9FF;
}
* {
font-family: -apple-system !important;
}
#textInput, #textOverlay {
font-family: -apple-system !important;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
.emoji {
font-family: 'Apple Color Emoji' !important;
}
</style>
</head>`
);
route.fulfill({
response,
body: modifiedHtml,
headers: {
...response.headers(),
'content-type': 'text/html'
}
});
} else {
route.continue();
}
});
await iPhonePage.goto('https://www.bratgenerator.com/', {
waitUntil: 'networkidle',
timeout: 30000
});
// Set viewport dan emulasi perangkat
await iPhonePage.setViewportSize(config.iPhoneViewport);
// Inject script untuk mengubah emoji
await iPhonePage.addScriptTag({
content: `
function replaceWithEmojiSpans() {
const textInput = document.querySelector('#textInput');
const textOverlay = document.querySelector('#textOverlay');
if (textInput && textOverlay) {
const emojiRegex = /[\u{1F300}-\u{1F9FF}]/gu;
const wrapEmojisWithSpan = (text) => {
return text.replace(emojiRegex, match =>
'<span class="emoji">' + match + '</span>'
);
};
const originalHandler = textInput.oninput;
textInput.oninput = function(e) {
if (originalHandler) originalHandler.call(this, e);
textOverlay.innerHTML = wrapEmojisWithSpan(this.value);
};
}
}
replaceWithEmojiSpans();
`
});
try {
await iPhonePage.click('#onetrust-accept-btn-handler', { timeout: 2000 });
} catch {}
await iPhonePage.evaluate(() => setupTheme('white'));
}
},
async generateBrat(text) {
await iPhonePage.fill('#textInput', text);
// Tunggu animasi dan render selesai
await iPhonePage.waitForTimeout(1000);
// Pastikan emoji sudah di-wrap dengan span
await iPhonePage.evaluate((text) => {
const textOverlay = document.querySelector('#textOverlay');
const emojiRegex = /[\u{1F300}-\u{1F9FF}]/gu;
const wrappedText = text.replace(emojiRegex, match =>
'<span class="emoji">' + match + '</span>'
);
textOverlay.innerHTML = wrappedText;
}, text);
await iPhonePage.waitForTimeout(500);
const overlay = iPhonePage.locator('#textOverlay');
return overlay.screenshot({
timeout: 5000,
scale: 'device'
});
},
async close() {
if (iPhoneBrowser) await iPhoneBrowser.close();
}
};
const app = express();
app.use(express.json());
app.use(cors());
app.set('json spaces', 3);
app.get('*', async (req, res) => {
try {
const { q, type } = req.query;
if (!q) {
return res.status(200).json({
name: 'HD Bart Generator API',
message: 'Parameter q di perlukan',
version: '2.1.0',
runtime: {
os: os.type(),
platform: os.platform(),
architecture: os.arch(),
cpuCount: os.cpus().length,
uptime: `${os.uptime()} seconds`,
memoryUsage: `${Math.round((os.totalmem() - os.freemem()) / 1024 / 1024)} MB used of ${Math.round(os.totalmem() / 1024 / 1024)} MB`
}
});
}
const imageBuffer = type === "iphone"
? await utils2.generateBrat(q)
: await utils.generateBrat(q);
res.set('Content-Type', 'image/png');
res.send(imageBuffer);
} catch (error) {
console.error(error);
res.status(500).json({
status: false,
message: 'Error generating image',
error: process.env.NODE_ENV === 'development' ? error.message : undefined
});
}
});
const PORT = process.env.PORT || 7860;
app.listen(PORT, async () => {
console.log(`Server running on port ${PORT}`);
await Promise.all([utils.initialize(), utils2.initialize()]);
});
process.on('SIGINT', async () => {
await Promise.all([utils.close(), utils2.close()]);
process.exit(0);
});