Last active
April 18, 2026 09:20
-
-
Save ayashiiiyo/5426682446e39c0f130d20a00fbc3b11 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Canvas, loadImage, FontLibrary } from 'skia-canvas' | |
| import fs from 'fs' | |
| import path from 'path' | |
| import { execSync } from 'child_process' | |
| const FONT_URL = 'https://raw.githubusercontent.com/uploader762/dat2/main/uploads/ebea8a-1776501237434.ttf' | |
| const FONT_PATH = './Poppins-Bold.ttf' | |
| const BG_URL = 'https://raw.githubusercontent.com/uploader762/dat1/main/uploads/4f8284-1776503052781.jpg' | |
| async function downloadFont(url, pathFile) { | |
| const res = await fetch(url) | |
| const buffer = Buffer.from(await res.arrayBuffer()) | |
| fs.writeFileSync(pathFile, buffer) | |
| } | |
| if (!fs.existsSync(FONT_PATH)) { | |
| await downloadFont(FONT_URL, FONT_PATH) | |
| } | |
| FontLibrary.use('Poppins', [FONT_PATH]) | |
| const left = 275 | |
| const right = 1011 | |
| const topY = 574 | |
| const bottomY = 1032 | |
| const centerX = (left + right) / 2 | |
| const centerY = 804 | |
| function wrapLines(ctx, text, maxWidth) { | |
| const words = text.split(' ') | |
| let line = '' | |
| const lines = [] | |
| for (let i = 0; i < words.length; i++) { | |
| const test = line + words[i] + ' ' | |
| const width = ctx.measureText(test).width | |
| if (width > maxWidth && i > 0) { | |
| lines.push(line) | |
| line = words[i] + ' ' | |
| } else { | |
| line = test | |
| } | |
| } | |
| lines.push(line) | |
| return lines | |
| } | |
| function drawText(ctx, text) { | |
| const maxWidth = right - left | |
| const maxHeight = bottomY - topY | |
| let fontSize = 95 | |
| let lines, lineHeight, totalHeight | |
| do { | |
| ctx.font = `${fontSize}px Poppins` | |
| lines = wrapLines(ctx, text, maxWidth) | |
| lineHeight = fontSize * 1.15 | |
| totalHeight = lines.length * lineHeight | |
| fontSize -= 2 | |
| } while (totalHeight > maxHeight && fontSize > 10) | |
| ctx.font = `${fontSize}px Poppins` | |
| ctx.fillStyle = '#000000' | |
| ctx.textAlign = 'center' | |
| ctx.textBaseline = 'middle' | |
| const finalLineHeight = fontSize * 1.15 | |
| const startY = centerY - (lines.length * finalLineHeight / 2) + (finalLineHeight / 2) | |
| lines.forEach((line, i) => { | |
| ctx.fillText(line, centerX, startY + (i * finalLineHeight)) | |
| }) | |
| } | |
| async function renderImage(text) { | |
| const canvas = new Canvas(1280, 1280) | |
| const ctx = canvas.getContext('2d') | |
| const bg = await loadImage(BG_URL) | |
| canvas.width = bg.width | |
| canvas.height = bg.height | |
| ctx.drawImage(bg, 0, 0) | |
| drawText(ctx, text) | |
| return await canvas.png | |
| } | |
| async function renderVideo(text) { | |
| const words = text.split(' ') | |
| const tmpDir = './tmp_frames' | |
| if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir) | |
| const frames = [] | |
| for (let i = 0; i < words.length; i++) { | |
| const partial = words.slice(0, i + 1).join(' ') | |
| const canvas = new Canvas(1280, 1280) | |
| const ctx = canvas.getContext('2d') | |
| const bg = await loadImage(BG_URL) | |
| canvas.width = bg.width | |
| canvas.height = bg.height | |
| ctx.drawImage(bg, 0, 0) | |
| drawText(ctx, partial) | |
| const framePath = path.join(tmpDir, `frame_${i}.png`) | |
| const buffer = await canvas.png | |
| fs.writeFileSync(framePath, buffer) | |
| frames.push(framePath) | |
| } | |
| const listPath = path.join(tmpDir, 'list.txt') | |
| let list = '' | |
| frames.forEach(f => { | |
| const abs = path.resolve(f).replace(/\\/g, '/') | |
| list += `file '${abs}'\n` | |
| list += `duration 0.8\n` | |
| }) | |
| const last = path.resolve(frames[frames.length - 1]).replace(/\\/g, '/') | |
| list += `file '${last}'\n` | |
| list += `duration 2\n` | |
| fs.writeFileSync(listPath, list) | |
| const listAbs = path.resolve(listPath).replace(/\\/g, '/') | |
| execSync(`ffmpeg -y -f concat -safe 0 -i "${listAbs}" -vf "fps=30,format=yuv420p" "output.mp4"`) | |
| frames.forEach(f => fs.unlinkSync(f)) | |
| fs.unlinkSync(listPath) | |
| fs.rmdirSync(tmpDir) | |
| return fs.readFileSync('output.mp4') | |
| } | |
| let handler = async (m, { conn, text, command }) => { | |
| try { | |
| if (!text) return m.reply(`Example: .${command} Halo dunia`) | |
| m.reply(global.wait) | |
| switch (command) { | |
| case 'bratnime': { | |
| const buffer = await renderImage(text) | |
| return await conn.sendSticker(m.chat, Buffer.from(buffer), m) | |
| } | |
| case 'bratnimevid': { | |
| const buffer = await renderVideo(text) | |
| const file = './temp.mp4' | |
| fs.writeFileSync(file, buffer) | |
| const out = './cut.mp4' | |
| execSync(`ffmpeg -y -i "${file}" -t 9.9 -c copy "${out}"`) | |
| const final = fs.readFileSync(out) | |
| fs.unlinkSync(file) | |
| fs.unlinkSync(out) | |
| return await conn.sendSticker(m.chat, Buffer.from(final), m) | |
| } | |
| } | |
| } catch (e) { | |
| m.reply(e.message) | |
| } | |
| } | |
| handler.help = ['bratnime', 'bratnimevid'] | |
| handler.tags = ['tools'] | |
| handler.command = ['bratnime', 'bratnimevid'] | |
| export default handler |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment