File size: 8,352 Bytes
2572638 bb24c41 2572638 bb24c41 2572638 bb24c41 2572638 bb24c41 2572638 bb24c41 2572638 bb24c41 2572638 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
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);
}); |