// code from goatstore // api: https://store.agi.bd const os = require("os"); const fs = require("fs"); const path = require("path"); const axios = require("axios"); const { createCanvas } = require("canvas"); const ffmpeg = require("fluent-ffmpeg"); const ffmpegPath = require("ffmpeg-static"); const ffprobePath = require("ffprobe-static").path; const checkDiskSpace = require("check-disk-space").default; ffmpeg.setFfmpegPath(ffmpegPath); ffmpeg.setFfprobePath(ffprobePath); const VIDEO_SHARE_URL = "https://drive.google.com/uc?export=download&id=1L2RXWLDvTaf6DqU3llRx8ioMjDSRUvKd"; const CACHE_DIR = path.join(__dirname, "cache"); const BG_VIDEO_PATH = path.join(CACHE_DIR, "uptime_bg.mp4"); const OUTPUT_DURATION = 19; const WIDTH = 1280; // 720p HD const HEIGHT = 720; if (!fs.existsSync(CACHE_DIR)) { fs.mkdirSync(CACHE_DIR, { recursive: true }); } function extractDriveId(url) { const match = url.match(/[?&]id=([a-zA-Z0-9_-]+)/) || url.match(/\/d\/([a-zA-Z0-9_-]+)/); return match ? match[1] : null; } async function downloadDriveFile(url, destPath) { const id = extractDriveId(url); if (!id) throw new Error("Invalid Google Drive URL"); let downloadUrl = "https://drive.google.com/uc?export=download&id=" + id; let response = await axios({ method: "get", url: downloadUrl, responseType: "stream", maxRedirects: 5, timeout: 90000, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } }); let contentType = (response.headers["content-type"] || "").toLowerCase(); if (contentType.includes("text/html")) { const textResponse = await axios.get(downloadUrl, { responseType: "text", timeout: 30000, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } }); const confirmMatch = textResponse.data.match(/confirm=([0-9A-Za-z_]+)/) || textResponse.data.match(/name="confirm" value="([^"]+)"/); if (confirmMatch) { downloadUrl = "https://drive.google.com/uc?export=download&confirm=" + confirmMatch[1] + "&id=" + id; } else { downloadUrl = "https://drive.google.com/uc?export=download&id=" + id + "&confirm=t"; } response = await axios({ method: "get", url: downloadUrl, responseType: "stream", maxRedirects: 5, timeout: 90000, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } }); } const writer = fs.createWriteStream(destPath); response.data.pipe(writer); return new Promise(function(resolve, reject) { writer.on("finish", function() { try { const stats = fs.statSync(destPath); if (stats.size < 50000) { fs.unlinkSync(destPath); reject(new Error("Downloaded file is too small. Probably not a valid video.")); } else { resolve(); } } catch (e) { reject(e); } }); writer.on("error", reject); response.data.on("error", reject); }); } async function ensureBackgroundVideo() { if (fs.existsSync(BG_VIDEO_PATH)) { const stats = fs.statSync(BG_VIDEO_PATH); if (stats.size > 50000) return BG_VIDEO_PATH; try { fs.unlinkSync(BG_VIDEO_PATH); } catch (e) {} } console.log("[UPTIME] Downloading background video..."); await downloadDriveFile(VIDEO_SHARE_URL, BG_VIDEO_PATH); console.log("[UPTIME] Background video downloaded successfully."); return BG_VIDEO_PATH; } function formatDuration(totalSeconds) { const d = Math.floor(totalSeconds / 86400); const h = Math.floor((totalSeconds % 86400) / 3600); const m = Math.floor((totalSeconds % 3600) / 60); const s = Math.floor(totalSeconds % 60); return d + "d " + h + "h " + m + "m " + s + "s"; } function formatBytes(bytes) { const gb = bytes / (1024 * 1024 * 1024); return gb.toFixed(2) + " GB"; } function getRamUsage() { const total = os.totalmem(); const free = os.freemem(); const used = total - free; const percent = ((used / total) * 100).toFixed(1); return formatBytes(used) + " / " + formatBytes(total) + " (" + percent + "%)"; } async function getRomUsage() { try { const diskPath = os.platform() === "win32" ? "C:" : "/"; const info = await checkDiskSpace(diskPath); const used = info.size - info.free; const percent = ((used / info.size) * 100).toFixed(1); return formatBytes(used) + " / " + formatBytes(info.size) + " (" + percent + "%)"; } catch (err) { return "N/A"; } } function getDeployerName() { const env = process.env; if (env.RENDER) return "Render"; if (env.RAILWAY_ENVIRONMENT || env.RAILWAY_PROJECT_ID) return "Railway"; if (env.REPL_ID || env.REPL_SLUG) return "Replit"; if (env.DYNO) return "Heroku"; if (env.KOYEB_APP_NAME) return "Koyeb"; if (env.FLY_APP_NAME) return "Fly.io"; if (env.CYCLIC_DEPLOYMENT_ID) return "Cyclic"; if (env.GLITCH_PROJECT_ID) return "Glitch"; if (env.PREFIX && String(env.PREFIX).includes("com.termux")) return "Termux"; if (env.PANEL || env.PTERODACTYL_INSTANCE) return "Pterodactyl Panel"; if (env.VERCEL) return "Vercel"; return os.platform() === "linux" ? "VPS / Linux Server" : "Local Machine"; } function roundRect(ctx, x, y, w, h, r) { if (w < 2 * r) r = w / 2; if (h < 2 * r) r = h / 2; 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 drawIconServer(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.strokeStyle = color; ctx.fillStyle = color; ctx.lineWidth = size * 0.08; ctx.lineJoin = "round"; const w = size, h = size * 0.6; roundRect(ctx, 0, 0, w, h * 0.45, size * 0.08); ctx.stroke(); roundRect(ctx, 0, h * 0.55, w, h * 0.45, size * 0.08); ctx.stroke(); ctx.beginPath(); ctx.arc(w * 0.15, h * 0.22, size * 0.045, 0, Math.PI * 2); ctx.arc(w * 0.15, h * 0.77, size * 0.045, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } function drawIconClock(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.strokeStyle = color; ctx.lineWidth = size * 0.09; ctx.lineCap = "round"; ctx.beginPath(); ctx.arc(size / 2, size / 2, size / 2 - size * 0.06, 0, Math.PI * 2); ctx.stroke(); ctx.beginPath(); ctx.moveTo(size / 2, size / 2); ctx.lineTo(size / 2, size * 0.25); ctx.moveTo(size / 2, size / 2); ctx.lineTo(size * 0.7, size / 2); ctx.stroke(); ctx.restore(); } function drawIconNode(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.fillStyle = color; const cx = size / 2, cy = size / 2, r = size / 2 - size * 0.05; ctx.beginPath(); for (let i = 0; i < 6; i++) { const angle = (Math.PI / 3) * i - Math.PI / 2; const px = cx + r * Math.cos(angle); const py = cy + r * Math.sin(angle); if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); } ctx.closePath(); ctx.fill(); ctx.restore(); } function drawIconCloud(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.fillStyle = color; ctx.beginPath(); ctx.arc(size * 0.32, size * 0.55, size * 0.28, Math.PI * 0.5, Math.PI * 1.5); ctx.arc(size * 0.58, size * 0.32, size * 0.24, Math.PI, Math.PI * 1.85); ctx.arc(size * 0.82, size * 0.55, size * 0.22, Math.PI * 1.4, Math.PI * 0.55, false); ctx.closePath(); ctx.fill(); ctx.restore(); } function drawIconRam(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.strokeStyle = color; ctx.fillStyle = color; ctx.lineWidth = size * 0.07; const w = size, h = size * 0.65, top = size * 0.15; roundRect(ctx, 0, top, w, h, size * 0.06); ctx.stroke(); for (let i = 0; i < 5; i++) { const px = (w / 6) * (i + 1); ctx.beginPath(); ctx.moveTo(px, top); ctx.lineTo(px, 0); ctx.stroke(); } ctx.restore(); } function drawIconDisk(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.strokeStyle = color; ctx.fillStyle = color; ctx.lineWidth = size * 0.08; ctx.beginPath(); ctx.arc(size / 2, size / 2, size / 2 - size * 0.05, 0, Math.PI * 2); ctx.stroke(); ctx.beginPath(); ctx.arc(size / 2, size / 2, size * 0.12, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.moveTo(size / 2, size / 2); ctx.lineTo(size * 0.9, size / 2); ctx.stroke(); ctx.restore(); } function drawIconUser(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.fillStyle = color; ctx.beginPath(); ctx.arc(size / 2, size * 0.32, size * 0.22, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(size / 2, size * 1.05, size * 0.42, Math.PI, 0, false); ctx.fill(); ctx.restore(); } function drawIconPulse(ctx, x, y, size, color) { ctx.save(); ctx.translate(x, y); ctx.strokeStyle = color; ctx.lineWidth = size * 0.12; ctx.lineJoin = "round"; ctx.lineCap = "round"; ctx.beginPath(); ctx.moveTo(0, size * 0.5); ctx.lineTo(size * 0.25, size * 0.5); ctx.lineTo(size * 0.4, size * 0.15); ctx.lineTo(size * 0.6, size * 0.85); ctx.lineTo(size * 0.75, size * 0.5); ctx.lineTo(size, size * 0.5); ctx.stroke(); ctx.restore(); } function buildOverlayPng(stats, outPath) { const canvas = createCanvas(WIDTH, HEIGHT); const ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, WIDTH, HEIGHT); const font = "Arial"; // Top Badge const badgeText = "MEHEDI SAITO SYSTEM RUNNING"; ctx.font = "bold 26px " + font; const badgeTextWidth = ctx.measureText(badgeText).width; const badgeW = badgeTextWidth + 90; const badgeH = 56; const badgeX = WIDTH - badgeW - 25; const badgeY = 22; ctx.fillStyle = "rgba(10,14,22,0.5)"; roundRect(ctx, badgeX, badgeY, badgeW, badgeH, badgeH / 2); ctx.fill(); ctx.lineWidth = 2; ctx.strokeStyle = "rgba(255,255,255,0.2)"; roundRect(ctx, badgeX, badgeY, badgeW, badgeH, badgeH / 2); ctx.stroke(); drawIconPulse(ctx, badgeX + 20, badgeY + 13, 30, "#00e676"); ctx.fillStyle = "#ffffff"; ctx.font = "bold 26px " + font; ctx.textBaseline = "middle"; ctx.fillText(badgeText, badgeX + 58, badgeY + badgeH / 2 + 1); // Bottom Panel const rows = [ { icon: drawIconServer, label: "SERVER UPTIME", value: stats.serverUptime }, { icon: drawIconClock, label: "BOT UPTIME", value: stats.botUptime }, { icon: drawIconNode, label: "NODE VERSION", value: stats.nodeVersion }, { icon: drawIconRam, label: "RAM USAGE", value: stats.ramUsage }, { icon: drawIconDisk, label: "ROM USAGE", value: stats.romUsage }, { icon: drawIconCloud, label: "DEPLOYER", value: stats.deployer }, { icon: drawIconUser, label: "OWNER", value: stats.ownerName } ]; const panelX = 30; const panelW = WIDTH - 60; const rowHeight = 68; const padTop = 24; const padBottom = 24; const panelH = rows.length * rowHeight + padTop + padBottom; const panelY = HEIGHT - panelH - 28; ctx.fillStyle = "rgba(8,10,18,0.5)"; roundRect(ctx, panelX, panelY, panelW, panelH, 20); ctx.fill(); ctx.lineWidth = 2; ctx.strokeStyle = "rgba(255,255,255,0.18)"; roundRect(ctx, panelX, panelY, panelW, panelH, 20); ctx.stroke(); rows.forEach(function(row, i) { const rowY = panelY + padTop + i * rowHeight; const iconSize = 32; const iconY = rowY + rowHeight / 2 - iconSize / 2; row.icon(ctx, panelX + 28, iconY, iconSize, "#4fd1ff"); ctx.textBaseline = "middle"; ctx.textAlign = "left"; ctx.fillStyle = "rgba(210,216,224,0.95)"; ctx.font = "bold 20px " + font; ctx.fillText(row.label, panelX + 78, rowY + rowHeight / 2); ctx.textAlign = "right"; ctx.fillStyle = "#ffffff"; ctx.font = "bold 26px " + font; ctx.fillText(String(row.value), panelX + panelW - 30, rowY + rowHeight / 2); ctx.textAlign = "left"; if (i < rows.length - 1) { ctx.strokeStyle = "rgba(255,255,255,0.12)"; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(panelX + 28, rowY + rowHeight); ctx.lineTo(panelX + panelW - 28, rowY + rowHeight); ctx.stroke(); } }); fs.writeFileSync(outPath, canvas.toBuffer("image/png")); return outPath; } function composeVideo(bgVideoPath, overlayPngPath, outPath) { return new Promise(function(resolve, reject) { const filter = "[0:v]scale=1280:720[bg];[bg][1:v]overlay=0:0[out]"; ffmpeg() .input(bgVideoPath) .inputOptions(["-stream_loop", "-1"]) .input(overlayPngPath) .complexFilter(filter) .outputOptions([ "-map", "[out]", "-map", "0:a?", "-t", "19", "-c:v", "libx264", "-preset", "ultrafast", // সবচেয়ে কম RAM/CPU ব্যবহার করে "-crf", "28", "-c:a", "aac", "-b:a", "96k", "-pix_fmt", "yuv420p", "-movflags", "+faststart", "-threads", "1", // low resource "-shortest" ]) .on("start", function(cmd) { console.log("[UPTIME] FFmpeg started"); }) .on("end", function() { console.log("[UPTIME] Video created successfully"); resolve(outPath); }) .on("error", function(err) { console.error("[UPTIME] FFmpeg error:", err.message); reject(err); }) .save(outPath); }); } module.exports = { config: { name: "uptime", aliases: ["system", "stm"], version: "3.1", author: "BADHON", role: 0, shortDescription: "Video uptime with system monitor + sound", longDescription: "Show bot uptime as 19s 720p HD mp4 with big text and original sound", category: "system", guide: "{pn}" }, onStart: async function ({ api, event }) { let overlayPath = null; let outPath = null; try { const bgVideoPath = await ensureBackgroundVideo(); const cardData = { serverUptime: formatDuration(os.uptime()), botUptime: formatDuration(process.uptime()), nodeVersion: process.version, ramUsage: getRamUsage(), romUsage: await getRomUsage(), deployer: getDeployerName(), ownerName: "Mehedi-saito" }; overlayPath = path.join(CACHE_DIR, "overlay_" + Date.now() + ".png"); buildOverlayPng(cardData, overlayPath); outPath = path.join(CACHE_DIR, "uptime_" + Date.now() + ".mp4"); await composeVideo(bgVideoPath, overlayPath, outPath); await api.sendMessage( { body: "📊 System Uptime", attachment: fs.createReadStream(outPath) }, event.threadID, event.messageID ); } catch (err) { console.error("[UPTIME] Error:", err); api.sendMessage( "❌ Failed to generate uptime video:\n" + (err.message || String(err)), event.threadID, event.messageID ); } finally { try { if (overlayPath && fs.existsSync(overlayPath)) fs.unlinkSync(overlayPath); if (outPath && fs.existsSync(outPath)) fs.unlinkSync(outPath); } catch (e) {} } } };