// code from goatstore // api: https://store.agi.bd const os = require("os"); const fs = require("fs"); const path = require("path"); let createCanvas, GIFEncoder; const W = 800, H = 450; const FRAMES = 20; const DELAY = 90; const C = { p1: "#a855f7", p2: "#7c3aed", p3: "#c084fc", pink: "#e879f9", gold: "#fbbf24", green: "#4ade80", text: "#ffffff", dim: "#9f8bb8", card: "rgba(40, 20, 70, 0.55)", border: "rgba(168, 85, 247, 0.25)" }; module.exports = { config: { name: "uptime2", version: "1.1", author: "GoatBot", countDown: 10, cooldowns: 10, role: 0, hasPermssion: 0, usePrefix: true, category: "system", commandCategory: "system", description: "Live animated uptime dashboard GIF", shortDescription: { en: "Live animated uptime dashboard" }, longDescription: { en: "Bot uptime, CPU, RAM, ping and system info in an animated neon-purple dashboard GIF" }, guide: { en: "{pn}" } }, onStart: async function ({ api, message, event }) { if (!message) message = makeMessage(api, event); try { createCanvas = createCanvas || require("canvas").createCanvas; GIFEncoder = GIFEncoder || require("gifencoder"); } catch (e) { return message.reply("❌ Module পাওয়া যায়নি। বটের ফোল্ডারে চালাও:\nnpm i canvas gifencoder\n\nError: " + e.message); } const t0 = Date.now(); let waitMsg; try { waitMsg = await message.reply("⏳ Generating live dashboard..."); } catch (e) { } const ping = Math.max(1, Date.now() - t0); const cpuUsage = await getCpuUsage(); const totalMem = os.totalmem(), freeMem = os.freemem(); const mu = process.memoryUsage(); const data = { uptime: process.uptime(), sysUptime: os.uptime(), ping, cpu: cpuUsage, ramPct: ((totalMem - freeMem) / totalMem) * 100, heapPct: (mu.heapUsed / mu.heapTotal) * 100, rssPct: Math.min(100, (mu.rss / totalMem) * 100), usedGB: (totalMem - freeMem) / 1073741824, totalGB: totalMem / 1073741824, rssMB: mu.rss / 1048576, heapMB: mu.heapUsed / 1048576, cpuModel: (os.cpus()[0] || {}).model || "Unknown CPU", cores: os.cpus().length, platform: `${os.type()} ${os.arch()}`, node: process.version }; const dir = path.join(__dirname, "tmp"); if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); const file = path.join(dir, `uptime2_${Date.now()}.gif`); try { await buildGif(data, file); await message.reply({ body: `🟢 Bot Uptime: ${fmtUptime(data.uptime)}\n📡 Ping: ${ping}ms`, attachment: fs.createReadStream(file) }); } catch (err) { console.error(err); await message.reply("❌ GIF তৈরি করতে সমস্যা হয়েছে: " + err.message); } finally { try { fs.unlinkSync(file); } catch (e) { } try { if (waitMsg && waitMsg.messageID) api.unsendMessage(waitMsg.messageID); } catch (e) { } } } }; // compatibility with older bot styles (run + api.sendMessage) module.exports.run = async function ({ api, event, message }) { return module.exports.onStart({ api, event, message }); }; function makeMessage(api, event) { return { reply: (msg) => new Promise((resolve) => api.sendMessage(msg, event.threadID, (err, info) => resolve(info || {}), event.messageID)) }; } /* ---------------- GIF BUILD ---------------- */ function buildGif(d, file) { return new Promise((resolve, reject) => { const enc = new GIFEncoder(W, H); const out = fs.createWriteStream(file); enc.createReadStream().pipe(out); out.on("finish", resolve); out.on("error", reject); enc.start(); enc.setRepeat(0); enc.setDelay(DELAY); enc.setQuality(12); const canvas = createCanvas(W, H); const ctx = canvas.getContext("2d"); for (let f = 0; f < FRAMES; f++) { drawFrame(ctx, d, f); enc.addFrame(ctx); } enc.finish(); }); } /* ---------------- HELPERS ---------------- */ function rr(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); } function ease(t) { return 1 - Math.pow(1 - Math.min(1, Math.max(0, t)), 3); } function fmtUptime(s) { s = Math.floor(s); const d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; return `${d}d ${h}h ${m}m ${sec}s`; } function fit(ctx, text, maxW) { if (ctx.measureText(text).width <= maxW) return text; while (text.length > 1 && ctx.measureText(text + "…").width > maxW) text = text.slice(0, -1); return text + "…"; } function txt(ctx, s, x, y, font, color, align = "left") { ctx.font = font; ctx.fillStyle = color; ctx.textAlign = align; ctx.textBaseline = "alphabetic"; ctx.fillText(s, x, y); } function card(ctx, x, y, w, h, title, icon) { rr(ctx, x, y, w, h, 16); ctx.fillStyle = C.card; ctx.fill(); ctx.strokeStyle = C.border; ctx.lineWidth = 1; ctx.stroke(); ctx.fillStyle = "rgba(168,85,247,0.18)"; rr(ctx, x + 14, y + 12, 24, 24, 8); ctx.fill(); txt(ctx, icon, x + 26, y + 29, "13px sans-serif", C.p3, "center"); txt(ctx, title, x + 46, y + 29, "bold 14px sans-serif", C.text); } async function getCpuUsage() { const snap = () => os.cpus().reduce((a, c) => { const t = Object.values(c.times).reduce((x, y) => x + y, 0); a.idle += c.times.idle; a.total += t; return a; }, { idle: 0, total: 0 }); const a = snap(); await new Promise(r => setTimeout(r, 400)); const b = snap(); const total = b.total - a.total; return total > 0 ? Math.min(100, Math.max(0, (1 - (b.idle - a.idle) / total) * 100)) : 0; } /* ---------------- FRAME ---------------- */ function drawFrame(ctx, d, f) { const p = f / FRAMES; // loop phase 0..1 const intro = ease((f + 1) / 12); // grow-in animation const pulse = (Math.sin(p * Math.PI * 2) + 1) / 2; // background let g = ctx.createLinearGradient(0, 0, W, H); g.addColorStop(0, "#0b0516"); g.addColorStop(1, "#1d0c33"); ctx.fillStyle = g; ctx.fillRect(0, 0, W, H); // moving glow const gx = W / 2 + Math.cos(p * Math.PI * 2) * 300, gy = 40 + Math.sin(p * Math.PI * 2) * 30; g = ctx.createRadialGradient(gx, gy, 0, gx, gy, 260); g.addColorStop(0, "rgba(168,85,247,0.35)"); g.addColorStop(1, "rgba(168,85,247,0)"); ctx.fillStyle = g; ctx.fillRect(0, 0, W, H); // header g = ctx.createLinearGradient(20, 15, 50, 45); g.addColorStop(0, C.pink); g.addColorStop(1, C.p2); ctx.fillStyle = g; rr(ctx, 20, 16, 32, 32, 10); ctx.fill(); txt(ctx, "⚡", 36, 39, "bold 18px sans-serif", "#fff", "center"); txt(ctx, "UPTIME", 62, 40, "bold 22px sans-serif", C.text); const nav = ["Dashboard", "System", "Memory", "Network"]; let nx = 250; nav.forEach((n, i) => { const w = 90; if (i === 0) { ctx.fillStyle = "rgba(168,85,247,0.25)"; rr(ctx, nx, 20, w, 28, 14); ctx.fill(); } txt(ctx, n, nx + w / 2, 39, "12px sans-serif", i === 0 ? C.text : C.dim, "center"); nx += w + 8; }); const now = new Date(); txt(ctx, now.toLocaleTimeString("en-GB"), W - 24, 39, "bold 14px sans-serif", C.p3, "right"); // live dot ctx.beginPath(); ctx.arc(W - 105, 34, 4 + pulse * 2, 0, Math.PI * 2); ctx.fillStyle = `rgba(74,222,128,${0.5 + pulse * 0.5})`; ctx.fill(); txt(ctx, "LIVE", W - 95, 38, "bold 10px sans-serif", C.green); drawUptimeRing(ctx, d, p, intro, pulse); drawResourceGauge(ctx, d, p, intro); drawPingChart(ctx, d, p, intro); drawMemoryBars(ctx, d, p, intro); drawSysInfo(ctx, d, p, pulse); } /* ---- card 1: uptime ring ---- */ function drawUptimeRing(ctx, d, p, intro, pulse) { const x = 20, y = 70, w = 250, h = 200; card(ctx, x, y, w, h, "Bot Uptime", "⏱"); const cx = x + w / 2, cy = y + 300 / 2 - 10 + 0, r = 52; const ccy = y + 106; // rotating dashed outer ring ctx.save(); ctx.setLineDash([4, 8]); ctx.lineDashOffset = -p * 48; ctx.strokeStyle = "rgba(192,132,252,0.45)"; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(cx, ccy, r + 14, 0, Math.PI * 2); ctx.stroke(); ctx.restore(); // track ctx.lineWidth = 10; ctx.lineCap = "round"; ctx.strokeStyle = "rgba(255,255,255,0.08)"; ctx.beginPath(); ctx.arc(cx, ccy, r, 0, Math.PI * 2); ctx.stroke(); // progress (fraction of current day) const frac = ((d.uptime % 86400) / 86400) * intro; const a0 = -Math.PI / 2, a1 = a0 + Math.max(0.05, frac) * Math.PI * 2; const g = ctx.createLinearGradient(cx - r, ccy - r, cx + r, ccy + r); g.addColorStop(0, C.pink); g.addColorStop(1, C.p2); ctx.strokeStyle = g; ctx.shadowColor = C.p1; ctx.shadowBlur = 12 + pulse * 8; ctx.beginPath(); ctx.arc(cx, ccy, r, a0, a1); ctx.stroke(); ctx.shadowBlur = 0; // knob ctx.beginPath(); ctx.arc(cx + Math.cos(a1) * r, ccy + Math.sin(a1) * r, 6, 0, Math.PI * 2); ctx.fillStyle = "#fff"; ctx.fill(); const s = Math.floor(d.uptime); const dd = Math.floor(s / 86400), hh = Math.floor((s % 86400) / 3600), mm = Math.floor((s % 3600) / 60); txt(ctx, dd > 0 ? `${dd}d ${hh}h` : `${hh}h ${mm}m`, cx, ccy + 3, "bold 20px sans-serif", C.text, "center"); txt(ctx, "ONLINE", cx, ccy + 20, "10px sans-serif", C.green, "center"); // stats const sy = y + 178; const st = [ [`${d.ping}ms`, "Ping"], [`${d.cores}`, "Cores"], [d.node, "Node"] ]; st.forEach((s2, i) => { const sx = x + 45 + i * 80; txt(ctx, s2[0], sx, sy - 6, "bold 13px sans-serif", C.text, "center"); txt(ctx, s2[1], sx, sy + 8, "10px sans-serif", C.dim, "center"); }); } /* ---- card 2: semicircle gauge ---- */ function drawResourceGauge(ctx, d, p, intro) { const x = 285, y = 70, w = 250, h = 200; card(ctx, x, y, w, h, "Resource Goals", "◎"); const cx = x + w / 2, cy = y + 118, r = 62; const A0 = Math.PI * 0.75, SPAN = Math.PI * 1.5; // ticks for (let i = 0; i <= 10; i++) { const a = A0 + (SPAN * i) / 10; ctx.strokeStyle = "rgba(255,255,255,0.18)"; ctx.lineWidth = 1.5; ctx.beginPath(); ctx.moveTo(cx + Math.cos(a) * (r + 12), cy + Math.sin(a) * (r + 12)); ctx.lineTo(cx + Math.cos(a) * (r + 18), cy + Math.sin(a) * (r + 18)); ctx.stroke(); } ctx.lineCap = "round"; ctx.lineWidth = 14; ctx.strokeStyle = "rgba(255,255,255,0.07)"; ctx.beginPath(); ctx.arc(cx, cy, r, A0, A0 + SPAN); ctx.stroke(); const v = (d.ramPct / 100) * intro; const aEnd = A0 + SPAN * Math.max(0.02, v); const g = ctx.createLinearGradient(cx - r, cy, cx + r, cy); g.addColorStop(0, C.p2); g.addColorStop(1, C.pink); ctx.strokeStyle = g; ctx.shadowColor = C.p1; ctx.shadowBlur = 14; ctx.beginPath(); ctx.arc(cx, cy, r, A0, aEnd); ctx.stroke(); ctx.shadowBlur = 0; // dots along the arc (like the reference design) for (let i = 0; i < 4; i++) { const a = A0 + SPAN * (0.1 + i * 0.07) * intro; ctx.beginPath(); ctx.arc(cx + Math.cos(a) * (r - 22), cy + Math.sin(a) * (r - 22), 4 - i * 0.6, 0, Math.PI * 2); ctx.fillStyle = C.p3; ctx.fill(); } ctx.beginPath(); ctx.arc(cx + Math.cos(aEnd) * r, cy + Math.sin(aEnd) * r, 7, 0, Math.PI * 2); ctx.fillStyle = "#fff"; ctx.fill(); txt(ctx, `${(d.ramPct * intro).toFixed(0)}%`, cx, cy + 5, "bold 26px sans-serif", C.text, "center"); txt(ctx, "RAM USED", cx, cy + 22, "10px sans-serif", C.dim, "center"); // bottom values const by = y + 186; ctx.fillStyle = C.p1; ctx.beginPath(); ctx.arc(x + 40, by - 4, 4, 0, Math.PI * 2); ctx.fill(); txt(ctx, `${(d.cpu * intro).toFixed(0)}%`, x + 52, by, "bold 14px sans-serif", C.text); txt(ctx, "CPU", x + 84, by, "11px sans-serif", C.dim); ctx.fillStyle = C.gold; ctx.beginPath(); ctx.arc(x + 140, by - 4, 4, 0, Math.PI * 2); ctx.fill(); txt(ctx, `${d.usedGB.toFixed(1)}/${d.totalGB.toFixed(1)}G`, x + 152, by, "bold 12px sans-serif", C.text); } /* ---- card 3: ping chart ---- */ function drawPingChart(ctx, d, p, intro) { const x = 550, y = 70, w = 230, h = 200; card(ctx, x, y, w, h, "Ping Monitor", "📡"); const gx = x + 16, gy = y + 52, gw = w - 32, gh = 100; // grid ctx.strokeStyle = "rgba(255,255,255,0.06)"; ctx.lineWidth = 1; for (let i = 0; i <= 4; i++) { ctx.beginPath(); ctx.moveTo(gx, gy + (gh * i) / 4); ctx.lineTo(gx + gw, gy + (gh * i) / 4); ctx.stroke(); } const N = 24, pts = []; for (let i = 0; i < N; i++) { const t = i + p * 3; const n = Math.sin(t * 0.9) * 0.35 + Math.sin(t * 2.1 + 1) * 0.2 + Math.sin(t * 0.37) * 0.25; const val = 0.5 + n * 0.5; pts.push([gx + (gw * i) / (N - 1), gy + gh - (val * 0.8 + 0.1) * gh * intro]); } // area let g = ctx.createLinearGradient(0, gy, 0, gy + gh); g.addColorStop(0, "rgba(168,85,247,0.45)"); g.addColorStop(1, "rgba(168,85,247,0)"); ctx.beginPath(); ctx.moveTo(pts[0][0], gy + gh); pts.forEach(q => ctx.lineTo(q[0], q[1])); ctx.lineTo(pts[N - 1][0], gy + gh); ctx.closePath(); ctx.fillStyle = g; ctx.fill(); // line ctx.beginPath(); pts.forEach((q, i) => (i ? ctx.lineTo(q[0], q[1]) : ctx.moveTo(q[0], q[1]))); ctx.strokeStyle = C.pink; ctx.lineWidth = 2.5; ctx.lineJoin = "round"; ctx.shadowColor = C.p1; ctx.shadowBlur = 8; ctx.stroke(); ctx.shadowBlur = 0; // scanning dot const si = Math.min(N - 1, Math.floor(p * (N - 1))); ctx.beginPath(); ctx.arc(pts[si][0], pts[si][1], 5, 0, Math.PI * 2); ctx.fillStyle = "#fff"; ctx.fill(); ctx.strokeStyle = "rgba(255,255,255,0.25)"; ctx.setLineDash([3, 4]); ctx.beginPath(); ctx.moveTo(pts[si][0], gy); ctx.lineTo(pts[si][0], gy + gh); ctx.stroke(); ctx.setLineDash([]); txt(ctx, `${d.ping} ms`, x + 18, y + 178, "bold 16px sans-serif", C.text); const q = d.ping < 150 ? "Excellent" : d.ping < 400 ? "Good" : "Slow"; txt(ctx, q, x + w - 18, y + 178, "bold 12px sans-serif", d.ping < 400 ? C.green : C.gold, "right"); } /* ---- card 4: memory bars ---- */ function drawMemoryBars(ctx, d, p, intro) { const x = 20, y = 285, w = 380, h = 145; card(ctx, x, y, w, h, "Memory Statistic", "▤"); const rows = [ ["Heap", d.heapPct, C.p1, `${d.heapMB.toFixed(0)} MB`], ["RSS", d.rssPct, C.gold, `${d.rssMB.toFixed(0)} MB`], ["System", d.ramPct, C.pink, `${d.usedGB.toFixed(1)} GB`] ]; rows.forEach((r, i) => { const ry = y + 56 + i * 28; txt(ctx, r[0], x + 20, ry + 10, "12px sans-serif", C.dim); const bx = x + 80, bw = w - 190, bh = 12; ctx.fillStyle = "rgba(255,255,255,0.07)"; rr(ctx, bx, ry, bw, bh, 6); ctx.fill(); const fw = Math.max(8, (bw * Math.min(100, r[1]) / 100) * intro); const g = ctx.createLinearGradient(bx, 0, bx + fw, 0); g.addColorStop(0, C.p2); g.addColorStop(1, r[2]); ctx.fillStyle = g; rr(ctx, bx, ry, fw, bh, 6); ctx.fill(); // shimmer ctx.save(); rr(ctx, bx, ry, fw, bh, 6); ctx.clip(); const sx = bx + ((p * 1.6) % 1) * (fw + 40) - 20; const sg = ctx.createLinearGradient(sx - 15, 0, sx + 15, 0); sg.addColorStop(0, "rgba(255,255,255,0)"); sg.addColorStop(0.5, "rgba(255,255,255,0.45)"); sg.addColorStop(1, "rgba(255,255,255,0)"); ctx.fillStyle = sg; ctx.fillRect(sx - 15, ry, 30, bh); ctx.restore(); txt(ctx, `${(r[1] * intro).toFixed(0)}%`, bx + bw + 12, ry + 10, "bold 12px sans-serif", C.text); txt(ctx, r[3], x + w - 16, ry + 10, "11px sans-serif", C.dim, "right"); }); } /* ---- card 5: system info ---- */ function drawSysInfo(ctx, d, p, pulse) { const x = 415, y = 285, w = 365, h = 145; card(ctx, x, y, w, h, "System Info", "☰"); const rows = [ ["Platform", d.platform], ["CPU", d.cpuModel], ["Host Up", fmtUptime(d.sysUptime)] ]; rows.forEach((r, i) => { const ry = y + 46 + i * 31; ctx.fillStyle = "rgba(255,255,255,0.05)"; rr(ctx, x + 12, ry, w - 24, 26, 10); ctx.fill(); const on = i === 0 ? pulse : 1; ctx.beginPath(); ctx.arc(x + 28, ry + 13, 4, 0, Math.PI * 2); ctx.fillStyle = `rgba(168,85,247,${0.5 + 0.5 * on})`; ctx.fill(); txt(ctx, r[0], x + 40, ry + 17, "bold 11px sans-serif", C.text); ctx.font = "11px sans-serif"; txt(ctx, fit(ctx, r[1], w - 160), x + w - 24, ry + 17, "11px sans-serif", C.dim, "right"); }); }