Spaces:
Paused
Paused
Update index.js
Browse files
index.js
CHANGED
|
@@ -125,6 +125,97 @@ async function createCustomSWGenerator({ profileImage, mainImage, caption = "Cus
|
|
| 125 |
return canvas.toBuffer('image/png');
|
| 126 |
}
|
| 127 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
/**
|
| 129 |
* Endpoint untuk membuat gambar status
|
| 130 |
* @route POST /generate-status
|
|
@@ -183,6 +274,30 @@ app.post('/generate', async (req, res) => {
|
|
| 183 |
}
|
| 184 |
});
|
| 185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
// Mulai server Express
|
| 187 |
app.listen(port, () => {
|
| 188 |
console.log(`Server berjalan di http://localhost:${port}`);
|
|
|
|
| 125 |
return canvas.toBuffer('image/png');
|
| 126 |
}
|
| 127 |
|
| 128 |
+
//Threads
|
| 129 |
+
|
| 130 |
+
async function generateThread(username, avatarPath, textContent) {
|
| 131 |
+
const canvas = createCanvas(1080, 300);
|
| 132 |
+
const ctx = canvas.getContext('2d');
|
| 133 |
+
|
| 134 |
+
// Background putih
|
| 135 |
+
ctx.fillStyle = '#ffffff';
|
| 136 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
| 137 |
+
|
| 138 |
+
// Teks "Utas pertama" dengan ikon bintang di bagian atas kiri
|
| 139 |
+
const starIcon = await loadImage(path.join('./star.svg');
|
| 140 |
+
ctx.drawImage(starIcon, 115, 20, 25, 25);
|
| 141 |
+
ctx.font = 'normal 25px Arial';
|
| 142 |
+
ctx.fillStyle = '#888888';
|
| 143 |
+
ctx.fillText('First thread', 145, 40);
|
| 144 |
+
|
| 145 |
+
// Titik tiga horizontal
|
| 146 |
+
const dotSize = 8;
|
| 147 |
+
const dotsXStart = canvas.width - 100;
|
| 148 |
+
const dotsY = 110;
|
| 149 |
+
for (let i = 0; i < 3; i++) {
|
| 150 |
+
ctx.beginPath();
|
| 151 |
+
ctx.arc(dotsXStart + i * 20, dotsY, dotSize / 2, 0, Math.PI * 2);
|
| 152 |
+
ctx.fillStyle = '#888888';
|
| 153 |
+
ctx.fill();
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
// Load avatar
|
| 157 |
+
const avatar = await loadImg(avatarPath);
|
| 158 |
+
const avatarSize = 80;
|
| 159 |
+
const avatarX = 40;
|
| 160 |
+
const avatarY = 80;
|
| 161 |
+
|
| 162 |
+
ctx.save();
|
| 163 |
+
ctx.beginPath();
|
| 164 |
+
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
| 165 |
+
ctx.closePath();
|
| 166 |
+
ctx.clip();
|
| 167 |
+
ctx.drawImage(avatar, avatarX, avatarY, avatarSize, avatarSize);
|
| 168 |
+
ctx.restore();
|
| 169 |
+
|
| 170 |
+
// Nama pengguna
|
| 171 |
+
const dUser = username.length > 15 ? username.slice(0, 15) + '...' : username;
|
| 172 |
+
ctx.font = 'bold 30px Arial';
|
| 173 |
+
ctx.fillStyle = '#000000';
|
| 174 |
+
ctx.fillText(dUser, 130, 110);
|
| 175 |
+
const usernameWidth = ctx.measureText(dUser).width;
|
| 176 |
+
|
| 177 |
+
// Tulisan 'sekarang'
|
| 178 |
+
ctx.font = 'normal 25px Arial';
|
| 179 |
+
ctx.fillStyle = '#888888';
|
| 180 |
+
ctx.fillText('Now', 130 + usernameWidth + 10, 110);
|
| 181 |
+
|
| 182 |
+
// Konten teks
|
| 183 |
+
ctx.font = 'normal 35px Arial';
|
| 184 |
+
ctx.fillStyle = '#000000';
|
| 185 |
+
const maxWidth = canvas.width - 40;
|
| 186 |
+
const lineHeight = 40;
|
| 187 |
+
wrapText(ctx, textContent, 40, 210, maxWidth, lineHeight);
|
| 188 |
+
|
| 189 |
+
// Reaksi
|
| 190 |
+
const heart = await loadImage('./heart.svg');
|
| 191 |
+
ctx.drawImage(heart, 45, 250, 35, 35);
|
| 192 |
+
ctx.font = 'normal 25px Arial';
|
| 193 |
+
ctx.fillStyle = '#000000';
|
| 194 |
+
ctx.fillText('99', 90, 275);
|
| 195 |
+
|
| 196 |
+
return canvas.toBuffer('image/png');
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
// Fungsi untuk membungkus teks panjang
|
| 200 |
+
function wrapText(ctx, text, x, y, maxWidth, lineHeight) {
|
| 201 |
+
const words = text.split(' ');
|
| 202 |
+
let line = '';
|
| 203 |
+
for (let n = 0; n < words.length; n++) {
|
| 204 |
+
const testLine = line + words[n] + ' ';
|
| 205 |
+
const metrics = ctx.measureText(testLine);
|
| 206 |
+
const testWidth = metrics.width;
|
| 207 |
+
if (testWidth > maxWidth && n > 0) {
|
| 208 |
+
ctx.fillText(line, x, y);
|
| 209 |
+
line = words[n] + ' ';
|
| 210 |
+
y += lineHeight;
|
| 211 |
+
} else {
|
| 212 |
+
line = testLine;
|
| 213 |
+
}
|
| 214 |
+
}
|
| 215 |
+
ctx.fillText(line, x, y);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
|
| 219 |
/**
|
| 220 |
* Endpoint untuk membuat gambar status
|
| 221 |
* @route POST /generate-status
|
|
|
|
| 274 |
}
|
| 275 |
});
|
| 276 |
|
| 277 |
+
app.post('/generate2', async (req, res) => {
|
| 278 |
+
try {
|
| 279 |
+
const { username, avatar, text } = req.body;
|
| 280 |
+
|
| 281 |
+
// Validasi input
|
| 282 |
+
if (!username || !text) {
|
| 283 |
+
return res.status(400).json({ error: 'Username and text are required.' });
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
const avatarPath = path.join(avatar || './icon.jpg');
|
| 287 |
+
const imageBuffer = await generateThread(username, avatarPath, text);
|
| 288 |
+
|
| 289 |
+
// Mengirimkan hasil sebagai gambar
|
| 290 |
+
res.writeHead(200, {
|
| 291 |
+
'Content-Type': 'image/png',
|
| 292 |
+
'Content-Disposition': 'inline; filename="thread.png"',
|
| 293 |
+
});
|
| 294 |
+
res.end(imageBuffer);
|
| 295 |
+
} catch (error) {
|
| 296 |
+
console.error('Error generating thread:', error);
|
| 297 |
+
res.status(500).json({ error: 'An error occurred while generating the thread.' });
|
| 298 |
+
}
|
| 299 |
+
});
|
| 300 |
+
|
| 301 |
// Mulai server Express
|
| 302 |
app.listen(port, () => {
|
| 303 |
console.log(`Server berjalan di http://localhost:${port}`);
|