maker / app.js
wudysoft's picture
Update app.js
32467d7 verified
import express from 'express';
import { chromium } from 'playwright';
import cors from 'cors';
import dotenv from 'dotenv';
import os from 'os';
import fetch from 'node-fetch';
import sharp from 'sharp';
dotenv.config();
const config = {
maxTextLength: 100,
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
};
let browser, page;
const utils = {
async initialize() {
if (!browser) {
browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: config.viewport,
userAgent: config.userAgent
});
await context.route('**/*', (route) => {
const url = route.request().url();
if (url.endsWith('.png') || url.endsWith('.jpg') || url.includes('google-analytics')) {
return route.abort();
}
route.continue();
});
page = await context.newPage();
await page.goto('https://www.bratgenerator.com/', { waitUntil: 'domcontentloaded', timeout: 10000 });
try {
await page.click('#onetrust-accept-btn-handler', { timeout: 2000 });
} catch { }
await page.evaluate(() => setupTheme('white'));
}
},
async generateBrat(text) {
await page.fill('#textInput', text);
const overlay = page.locator('#textOverlay');
return overlay.screenshot({ timeout: 3000 });
},
async close() {
if (browser) await browser.close();
}
};
const app = express();
app.use(express.json());
app.use(cors());
app.get('/brat', async (req, res) => {
try {
const { q } = req.query;
if (!q) {
return res.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 = 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 font = 'BlueArchive';
const crossBuffer = Buffer.from('<svg width="480" height="200" version="1.1"><polygon points="252,0 159,190 165,190 287,0" style="fill:#fff" /></svg>');
const haloBuffer = Buffer.from('<svg width="480" height="200" version="1.1"><polygon points="252,0 159,190 165,190 287,0" style="fill:#fff" /></svg>');
const splitText = (text) => {
if (Array.isArray(text)) return text;
if (text.includes(' ')) {
return text.split(' ').filter(i => i.trim());
} else if (text.match(/^[A-Z][a-z]*[A-Z][a-z]*$/)) {
return text.replace(/[A-Z]/g, t => ' ' + t).trim().split(' ');
} else {
const h = Math.floor(text.length / 2);
return [text.substring(0, h), text.substring(h)];
}
};
const baLogo = async (text, left = 0) => {
const [head, tail] = splitText(text);
if (!head || !tail) throw new Error('Invalid input text');
let width = 32, height = 260;
const top = 208;
const matrix = [[1, -0.35], [0, 1]];
const comps = [];
const headPart = sharp({
text: {
font,
text: `<span color="#208ef7" size="144pt">${head}</span>`,
dpi: 72,
rgba: true,
}
}).affine(matrix, {
background: '#fff0',
interpolator: sharp.interpolators.nohalo
}).png();
const headMeta = await headPart.metadata();
const w = width + headMeta.width - 162;
const dl = w < 0 ? 0 : w + left;
const tailPart = sharp({
text: {
font,
text: `<span color="#208ef7" size="144pt">${head}<span color="#2b2b2b" size="144pt">${tail}</span></span>`,
dpi: 72,
rgba: true,
}
}).affine(matrix, {
background: '#fff0',
interpolator: sharp.interpolators.nohalo
}).png();
const tailMeta = await tailPart.metadata();
comps.push({
input: await tailPart.toBuffer(),
left: width,
top,
});
comps.push({
input: crossBuffer,
left: dl + 4,
top: 4,
});
width += (tailMeta.width < 256 ? 256 : tailMeta.width ) + 64;
height += 144;
if (width < 500) width = 500;
return sharp({
create: {
width, height,
channels: 4,
background: '#fff',
},
}).composite(comps).png();
};
app.get('/balogo', async (req, res) => {
try {
const { text, text2 } = req.query;
if (!text) return res.status(400).send('Text is required');
const logoImage = await baLogo(text);
res.set('Content-Type', 'image/png');
res.send(await logoImage.toBuffer());
} catch (error) {
res.status(500).send('Error generating logo: ' + error.message);
}
});
async function baLogov2(textL = "蔚蓝", textR = "档案", x = "-15", y = "0", tp = false) {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
});
const page = await context.newPage();
await page.goto('https://symbolon.pages.dev/');
await page.waitForSelector('#canvas');
await page.fill('#textL', textL);
await page.fill('#textR', textR);
await page.fill('#graphX', x);
await page.fill('#graphY', y);
await page.waitForTimeout(500);
const imageBuffer = await page.$eval('#canvas', (canvas) => {
return canvas.toDataURL('image/png').split(',')[1];
});
const buffer = Buffer.from(imageBuffer, 'base64');
await browser.close();
return buffer;
}
app.get('/balogo/v2', async (req, res) => {
try {
const { textL = "蔚蓝", textR = "档案", x = "-15", y = "0", tp = "false" } = req.query;
const tpBool = tp === "true";
const imageBuffer = await baLogov2(textL, textR, x, y, tpBool);
res.setHeader('Content-Type', 'image/png');
res.send(imageBuffer);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Error generating logo" });
}
});
async function baLogov3(textL = "蔚蓝", textR = "档案") {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
});
const page = await context.newPage();
await page.goto('https://appleneko2001-bluearchive-logo.vercel.app/');
try {
await page.waitForSelector('#canvas', { timeout: 30000 });
} catch (err) {
console.error('Canvas tidak ditemukan:', err);
}
try {
await page.waitForSelector('#textL', { state: 'visible', timeout: 10000 });
await page.fill('#textL', textL);
} catch (err) {
console.error('Elemen #textL gagal diisi:', err);
}
try {
await page.waitForSelector('#textR', { state: 'visible', timeout: 10000 });
await page.fill('#textR', textR);
} catch (err) {
console.error('Elemen #textR gagal diisi:', err);
}
await page.waitForTimeout(2000);
const imageBuffer = await page.$eval('#canvas', (canvas) => {
return canvas.toDataURL('image/png').split(',')[1];
});
const buffer = Buffer.from(imageBuffer, 'base64');
await browser.close();
return buffer;
}
app.get('/balogo/v3', async (req, res) => {
try {
const { textL = "蔚蓝", textR = "档案" } = req.query;
const imageBuffer = await baLogov3(textL, textR);
res.setHeader('Content-Type', 'image/png');
res.send(imageBuffer);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Error generating logo" });
}
});
async function baLogov4(textL = "蔚蓝", textR = "档案") {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
});
const page = await context.newPage();
await page.goto('https://ba.api.hli.icu/');
try {
await page.waitForSelector('#canvas', { timeout: 30000 });
} catch (err) {
console.error('Canvas tidak ditemukan:', err);
}
try {
await page.waitForSelector('#textL', { state: 'visible', timeout: 10000 });
await page.fill('#textL', textL);
} catch (err) {
console.error('Elemen #textL gagal diisi:', err);
}
try {
await page.waitForSelector('#textR', { state: 'visible', timeout: 10000 });
await page.fill('#textR', textR);
} catch (err) {
console.error('Elemen #textR gagal diisi:', err);
}
await page.waitForTimeout(500);
const imageBuffer = await page.$eval('#canvas', (canvas) => {
return canvas.toDataURL('image/png').split(',')[1];
});
const buffer = Buffer.from(imageBuffer, 'base64');
await browser.close();
return buffer;
}
app.get('/balogo/v4', async (req, res) => {
try {
const { textL = "蔚蓝", textR = "档案" } = req.query;
const imageBuffer = await baLogov4(textL, textR);
res.setHeader('Content-Type', 'image/png');
res.send(imageBuffer);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Error generating logo" });
}
});
app.get('/rayso', async (req, res) => {
const { code, title = 'app.js', theme = 'supabase', language = '', darkMode = 'true', background = 'false' } = req.query;
if (!code)
return res.status(400).json({ error: 'Parameter "code" (Base64 encoded) diperlukan' });
try {
const encodedCode = Buffer.from(code, 'base64');
const url = `https://www.ray.so/#code=${encodeURIComponent(encodedCode)}&title=${encodeURIComponent(title)}&theme=${theme}&language=${language}&background=${background}&darkMode=${darkMode}`;
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
});
const page = await context.newPage();
await page.goto(url);
await page.waitForSelector('.Frame_frame__rcr69');
const elementHandle = await page.$('.Frame_frame__rcr69');
const screenshotBuffer = await elementHandle.screenshot({ fullPage: true });
await browser.close();
res.setHeader('Content-Type', 'image/png');
return res.status(200).end(screenshotBuffer);
} catch (error) {
return res.status(500).json({ error: 'Gagal mengambil screenshot', details: error.message });
}
});
app.get('/carbon', async (req, res) => {
const { code, theme } = req.query;
if (!code) return res.status(400).json({ error: 'Parameter "code" diperlukan.' });
if (!theme) return res.status(400).json({ error: 'Parameter "theme" diperlukan.' });
try {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
acceptDownloads: true
});
const page = await context.newPage();
await page.goto('https://carbon.now.sh/');
await page.click('input[aria-labelledby="theme-dropdown"]');
await page.keyboard.type(theme);
await page.keyboard.press('Enter');
await page.click('pre.CodeMirror-line span[role="presentation"]');
await page.keyboard.press('Control+A');
await page.keyboard.press('Backspace');
await page.keyboard.type(code);
await page.waitForSelector('button[data-cy="quick-export-button"]');
const [download] = await Promise.all([
page.waitForEvent('download'),
page.click('button[data-cy="quick-export-button"]')
]);
const downloadPath = await download.path();
res.setHeader('Content-Type', 'application/octet-stream');
return res.status(200).sendFile(downloadPath);
} catch (error) {
return res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
} finally {
await browser.close();
}
});
app.get('/recoded', async (req, res) => {
const { code, colors, font, lang, bg } = req.query;
if (!code) return res.status(400).json({ error: 'Parameter "code" diperlukan.' });
if (!colors) return res.status(400).json({ error: 'Parameter "colors" diperlukan.' });
if (!font) return res.status(400).json({ error: 'Parameter "font" diperlukan.' });
if (!lang) return res.status(400).json({ error: 'Parameter "lang" diperlukan.' });
if (!bg) return res.status(400).json({ error: 'Parameter "bg" diperlukan.' });
try {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
acceptDownloads: true,
});
const page = await context.newPage();
await page.goto('https://recoded.netlify.app/');
await page.fill('textarea.npm__react-simple-code-editor__textarea', code);
await page.click('div.input-box[style*="120px"]:has-text("VS Code Dark")');
await page.keyboard.type(colors);
await page.keyboard.press('Enter');
await page.click('div[data-testid="font-select"]');
await page.keyboard.type(font);
await page.keyboard.press('Enter');
await page.click('div[data-testid="language-select"]');
await page.keyboard.type(lang);
await page.keyboard.press('Enter');
await page.click('div[data-testid="background-color-select"]');
await page.keyboard.type(bg);
await page.keyboard.press('Enter');
const [download] = await Promise.all([
page.waitForEvent('download'),
page.click('button.button.export')
]);
const downloadPath = await download.path();
res.setHeader('Content-Type', 'image/png');
return res.status(200).send(downloadPath);
} catch (error) {
return res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
} finally {
await browser.close();
}
});
app.get('/chalkist', async (req, res) => {
const { code, title } = req.query;
if (!code) return res.status(400).json({ error: 'Parameter "code" diperlukan.' });
if (!title) return res.status(400).json({ error: 'Parameter "title" diperlukan.' });
let browser;
try {
browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
});
const page = await context.newPage();
await page.goto('https://chalk.ist/');
// Isi kolom judul
const titleSelector = 'div[data-placeholder="Untitled..."]';
await page.focus(titleSelector);
await page.keyboard.type(title);
// Isi kolom kode
const codeSelector = 'textarea.editor.font-config';
await page.fill(codeSelector, code);
// Tunggu elemen muncul untuk screenshot
const screenshotSelector = 'div[data-editor-frame]';
await page.waitForSelector(screenshotSelector);
// Ambil screenshot elemen
const element = await page.$(screenshotSelector);
const screenshotBuffer = await element.screenshot();
res.setHeader('Content-Type', 'image/png');
res.status(200).send(screenshotBuffer);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
} finally {
if (browser) await browser.close();
}
});
app.get('/brat/v2', async (req, res) => {
const { text } = req.query;
if (!text) return res.status(400).json({ error: 'Parameter "text" diperlukan.' });
try {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
acceptDownloads: true,
});
const page = await context.newPage();
await page.goto('https://brat-generator.net/');
await page.fill('input[class="w-full p-3 text-base border border-gray-200 rounded-lg mb-5 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-colors"]', text);
try {
await page.waitForSelector('button[class="px-5 py-3 text-sm font-medium rounded-lg flex items-center justify-between flex-1 transition-all bg-white border-2 border-blue-500 text-blue-600"]', { visible: true });
await page.click('button[class="px-5 py-3 text-sm font-medium rounded-lg flex items-center justify-between flex-1 transition-all bg-white border-2 border-blue-500 text-blue-600"]');
} catch (error) {
console.log("Tombol 'White Background' tidak ditemukan atau tidak terlihat, melewati langkah ini.");
}
try {
await page.waitForSelector('button[class="w-full mt-5 px-5 py-3 text-sm font-medium rounded-lg transition-all bg-blue-500 text-white hover:bg-blue-600"]', { visible: true });
await page.click('button[class="w-full mt-5 px-5 py-3 text-sm font-medium rounded-lg transition-all bg-blue-500 text-white hover:bg-blue-600"]');
} catch (error) {
console.log("Tombol 'Download Image' tidak ditemukan atau tidak terlihat, melewati langkah ini.");
}
await page.waitForSelector('canvas[class="absolute top-0 left-0 w-full h-full bg-white shadow-inner"]', { visible: true });
await page.waitForTimeout(800);
const canvas = await page.$('canvas[class="absolute top-0 left-0 w-full h-full bg-white shadow-inner"]');
const screenshot = await canvas.screenshot();
res.setHeader('Content-Type', 'image/png');
res.status(200).send(screenshot);
} catch (error) {
return res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
} finally {
await browser.close();
}
});
app.get('/', async (req, res) => {
res.status(200).send('Maker API');
});
const PORT = process.env.PORT || 7860;
app.listen(PORT, async () => {
console.log(`Server running on port ${PORT}`);
await utils.initialize();
});
process.on('SIGINT', async () => {
await utils.close();
process.exit(0);
});