goat
command
prefix
CPANEL style prefix panel with video
0
views
0
likes
0
installs
raw source
const fs = require("fs-extra");
const moment = require("moment-timezone");
const path = require("path");
const { createCanvas } = require("canvas");
const os = require("os");
const CACHE_DIR = path.join(__dirname, "cache");
const VIDEO_PATH = path.join(CACHE_DIR, "prefix.mp4");
module.exports = {
config: {
name: "prefix",
version: "7.0.0",
author: "Efx Asif",
countDown: 5,
role: 0,
description: "CPANEL style prefix panel with video",
category: "config"
},
langs: {
en: {
onlyAdmin:
"╭━━━〔 ⛔ ACCESS DENIED 〕━━━╮\n" +
"┃\n" +
"┃ Only bot admin can change\n" +
"┃ the global prefix.\n" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
confirmGlobal:
"╭━━━〔 🌈 GLOBAL PREFIX 〕━━━╮\n" +
"┃\n" +
"┃ 🆕 New Prefix : 『 %1 』\n" +
"┃ 👑 Owner : Efx Asif\n" +
"┃\n" +
"┃ 👉 React to confirm.\n" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
confirmThisThread:
"╭━━━〔 🌈 GROUP PREFIX 〕━━━╮\n" +
"┃\n" +
"┃ 🆕 New Prefix : 『 %1 』\n" +
"┃ 👑 Owner : Efx Asif\n" +
"┃\n" +
"┃ 👉 React to confirm.\n" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
successGlobal:
"╭━━━〔 ✅ GLOBAL UPDATED 〕━━━╮\n" +
"┃\n" +
"┃ 🌈 New Prefix : 『 %1 』\n" +
"┃ 👑 Owner : Efx Asif\n" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
successThisThread:
"╭━━━〔 ✅ GROUP UPDATED 〕━━━╮\n" +
"┃\n" +
"┃ 🌈 New Prefix : 『 %1 』\n" +
"┃ 👑 Owner : Efx Asif\n" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
reset:
"╭━━━〔 🔄 PREFIX RESET 〕━━━╮\n" +
"┃\n" +
"┃ ✅ Group prefix reset successful!\n" +
"┃ 🔰 System Prefix : 『 %1 』\n" +
"┃ 👑 Owner : Efx Asif\n" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯"
}
},
// ==========================================
// HOSTING
// ==========================================
getHostingName() {
const env = process.env;
if (env.RENDER) return "Render";
if (env.RAILWAY_ENVIRONMENT) return "Railway";
if (env.VERCEL) return "Vercel";
if (env.REPL_ID) return "Replit";
if (env.FLY_APP_NAME) return "Fly.io";
if (env.AWS_EXECUTION_ENV) return "AWS";
if (env.DYNO) return "Heroku";
if (env.GITHUB_ACTIONS) return "GitHub";
return "VPS / Local";
},
// ==========================================
// UPTIME
// ==========================================
formatUptime(ms) {
let sec = Math.floor(ms / 1000);
if (sec <= 0)
return "0s";
const days = Math.floor(sec / 86400);
sec %= 86400;
const hours = Math.floor(sec / 3600);
sec %= 3600;
const minutes = Math.floor(sec / 60);
const seconds = sec % 60;
const parts = [];
if (days) parts.push(`${days}d`);
if (hours) parts.push(`${hours}h`);
if (minutes) parts.push(`${minutes}m`);
if (!parts.length || seconds)
parts.push(`${seconds}s`);
return parts.join(" ");
},
// ==========================================
// FONT FIT
// ==========================================
fitFont(ctx, text, maxWidth, size) {
let fontSize = size;
while (fontSize > 8) {
ctx.font = `bold ${fontSize}px Arial`;
if (
ctx.measureText(String(text)).width <=
maxWidth
) {
break;
}
fontSize--;
}
return `bold ${fontSize}px Arial`;
},
// ==========================================
// CIRCLE
// ==========================================
drawCircle(ctx, x, y, radius, color) {
ctx.save();
ctx.shadowColor = color;
ctx.shadowBlur = 28;
ctx.beginPath();
ctx.arc(
x,
y,
radius,
0,
Math.PI * 2
);
ctx.fillStyle = "#08101c";
ctx.fill();
ctx.shadowBlur = 0;
ctx.strokeStyle = color;
ctx.lineWidth = 3;
ctx.stroke();
ctx.beginPath();
ctx.arc(
x,
y,
radius - 9,
0,
Math.PI * 2
);
ctx.strokeStyle =
"rgba(255,255,255,0.10)";
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
},
// ==========================================
// CONNECTION
// ==========================================
drawConnection(
ctx,
x1,
y1,
x2,
y2,
color
) {
ctx.save();
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.globalAlpha = 0.18;
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.restore();
},
// ==========================================
// GRID
// ==========================================
drawGrid(ctx, width, height, color) {
ctx.save();
ctx.globalAlpha = 0.055;
ctx.strokeStyle = color;
ctx.lineWidth = 1;
const gap = 45;
for (let x = 0; x < width; x += gap) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = 0; y < height; y += gap) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
ctx.restore();
},
// ==========================================
// CENTER TEXT
// ==========================================
drawCenterText(ctx, x, y, color) {
ctx.save();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "bold 27px Arial";
ctx.shadowColor = color;
ctx.shadowBlur = 18;
ctx.fillStyle = color;
ctx.fillText(
"PREFIX",
x,
y
);
ctx.restore();
},
// ==========================================
// STAT TEXT
// ==========================================
drawStatText(ctx, circle, color) {
ctx.save();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = circle.valueFont;
ctx.shadowColor = color;
ctx.shadowBlur = 12;
ctx.fillStyle = color;
ctx.fillText(
circle.value,
circle.x,
circle.y - 7
);
ctx.shadowBlur = 0;
ctx.font = circle.labelFont;
ctx.fillStyle = "#c5ccd6";
ctx.fillText(
circle.label,
circle.x,
circle.y + 13
);
ctx.restore();
},
// ==========================================
// CREATE CPANEL IMAGE
// ==========================================
createCPanelImage: async function ({
groupName,
systemPrefix,
groupPrefix,
owner
}) {
await fs.ensureDir(CACHE_DIR);
const width = 900;
const height = 600;
const canvas =
createCanvas(width, height);
const ctx =
canvas.getContext("2d");
const centerX = width / 2;
const centerY = height / 2 + 15;
const time =
moment()
.tz("Asia/Dhaka")
.format("hh:mm A");
const date =
moment()
.tz("Asia/Dhaka")
.format("DD MMM YYYY");
const stats = [
{
label: "SYSTEM",
value: systemPrefix
},
{
label: "GROUP",
value: groupPrefix
},
{
label: "NODE",
value: process.version.replace("v", "")
},
{
label: "HOST",
value: this.getHostingName()
},
{
label: "UPTIME",
value: this.formatUptime(
process.uptime() * 1000
)
},
{
label: "TIME",
value: time
},
{
label: "DATE",
value: date
},
{
label: "OWNER",
value: owner
},
{
label: "GROUP",
value: groupName
},
{
label: "STATUS",
value: "ONLINE"
}
];
const orbitRadius = 210;
const circleRadius = 67;
const statCircles =
stats.map((stat, index) => {
const angle =
(Math.PI * 2 / stats.length) *
index -
Math.PI / 2;
const x =
centerX +
orbitRadius *
Math.cos(angle);
const y =
centerY +
orbitRadius *
Math.sin(angle);
return {
x,
y,
label: stat.label,
value: String(stat.value),
valueFont:
this.fitFont(
ctx,
stat.value,
100,
15
),
labelFont:
this.fitFont(
ctx,
stat.label,
100,
10
)
};
});
// ========================================
// STATIC FRAME
// ========================================
const hue =
Math.floor(
(Date.now() / 25) % 360
);
const glowColor =
`hsl(${hue}, 100%, 65%)`;
// Background
const bg =
ctx.createLinearGradient(
0,
0,
width,
height
);
bg.addColorStop(0, "#030611");
bg.addColorStop(0.5, "#0a1020");
bg.addColorStop(1, "#020409");
ctx.fillStyle = bg;
ctx.fillRect(
0,
0,
width,
height
);
// Grid
this.drawGrid(
ctx,
width,
height,
glowColor
);
// Header
ctx.textAlign = "left";
ctx.font =
"bold 27px Arial";
ctx.shadowColor =
glowColor;
ctx.shadowBlur = 14;
ctx.fillStyle = "#ffffff";
ctx.fillText(
"🤖 ASIF EVO BOT V3",
30,
38
);
ctx.shadowBlur = 0;
ctx.font =
"bold 12px Arial";
ctx.fillStyle =
glowColor;
ctx.fillText(
"PREFIX SYSTEM PANEL",
32,
59
);
// Time
ctx.textAlign = "right";
ctx.font =
"bold 15px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText(
time,
width - 30,
38
);
ctx.font =
"bold 10px Arial";
ctx.fillStyle = "#8994a6";
ctx.fillText(
"BANGLADESH TIME",
width - 30,
58
);
// Connections
statCircles.forEach(circle => {
this.drawConnection(
ctx,
centerX,
centerY,
circle.x,
circle.y,
glowColor
);
});
// Center
this.drawCircle(
ctx,
centerX,
centerY,
105,
glowColor
);
this.drawCenterText(
ctx,
centerX,
centerY,
glowColor
);
// Stats
statCircles.forEach(circle => {
this.drawCircle(
ctx,
circle.x,
circle.y,
circleRadius,
glowColor
);
this.drawStatText(
ctx,
circle,
glowColor
);
});
// Footer
ctx.textAlign = "center";
ctx.font =
"bold 12px Arial";
ctx.fillStyle =
"#707b8c";
ctx.fillText(
"ASIF EVO • PREFIX SYSTEM • 🟢 ONLINE",
centerX,
height - 20
);
const imagePath =
path.join(
CACHE_DIR,
`prefix_cpanel_${Date.now()}.png`
);
await fs.writeFile(
imagePath,
canvas.toBuffer("image/png")
);
return imagePath;
},
// ==========================================
// SEND PREFIX PANEL + VIDEO
// ==========================================
sendPrefixPanel: async function ({
message,
event,
threadsData
}) {
const systemPrefix =
global.GoatBot.config.prefix;
const groupPrefix =
global.utils.getPrefix(
event.threadID
);
const threadInfo =
await threadsData.get(
event.threadID
);
const groupName =
threadInfo?.threadName ||
"Unknown Group";
const owner =
global.GoatBot.config.adminName ||
"Efx Asif";
const image =
await this.createCPanelImage({
groupName,
systemPrefix,
groupPrefix,
owner
});
// Image + video
if (await fs.pathExists(VIDEO_PATH)) {
return message.reply({
body:
`╭━━━〔 🌈 PREFIX PANEL 〕━━━╮\n` +
`┃ 🔰 System : 『 ${systemPrefix} 』\n` +
`┃ 👥 Group : 『 ${groupPrefix} 』\n` +
`┃ 🟢 Status : ONLINE\n` +
`┃\n` +
`╰━━━━━━━━━━━━━━━━━━━━╯`,
attachment: [
fs.createReadStream(image),
fs.createReadStream(VIDEO_PATH)
]
});
}
// Video missing → image only
return message.reply({
body:
`🌈 PREFIX SYSTEM\n` +
`🔰 System Prefix : 『 ${systemPrefix} 』\n` +
`👥 Group Prefix : 『 ${groupPrefix} 』\n` +
`🟢 Status : ONLINE`,
attachment:
fs.createReadStream(image)
});
},
// ==========================================
// COMMAND
// ==========================================
onStart: async function ({
message,
role,
args,
commandName,
event,
threadsData,
getLang
}) {
// Show panel
if (!args[0]) {
return this.sendPrefixPanel({
message,
event,
threadsData
});
}
// Reset
if (
args[0].toLowerCase() === "reset"
) {
await threadsData.set(
event.threadID,
null,
"data.prefix"
);
return message.reply(
getLang(
"reset",
global.GoatBot.config.prefix
)
);
}
const newPrefix =
args[0];
const setGlobal =
args[1] === "-g";
// Global admin check
if (
setGlobal &&
role < 2
) {
return message.reply(
getLang("onlyAdmin")
);
}
const confirmMsg =
setGlobal
? getLang(
"confirmGlobal",
newPrefix
)
: getLang(
"confirmThisThread",
newPrefix
);
message.reply(
confirmMsg,
(err, info) => {
if (err)
return;
global.GoatBot.onReaction.set(
info.messageID,
{
commandName,
author:
event.senderID,
newPrefix,
setGlobal
}
);
}
);
},
// ==========================================
// REACTION
// ==========================================
onReaction: async function ({
event,
message,
threadsData,
Reaction,
getLang
}) {
if (
event.userID !==
Reaction.author
) {
return;
}
global.GoatBot.onReaction.delete(
event.messageID
);
if (Reaction.setGlobal) {
global.GoatBot.config.prefix =
Reaction.newPrefix;
fs.writeFileSync(
global.client.dirConfig,
JSON.stringify(
global.GoatBot.config,
null,
2
)
);
return message.reply(
getLang(
"successGlobal",
Reaction.newPrefix
)
);
}
await threadsData.set(
event.threadID,
Reaction.newPrefix,
"data.prefix"
);
return message.reply(
getLang(
"successThisThread",
Reaction.newPrefix
)
);
},
// ==========================================
// AUTO PREFIX CHAT
// ==========================================
onChat: async function ({
event,
message,
threadsData
}) {
if (
!event.body ||
event.body.toLowerCase() !==
"prefix"
) {
return;
}
return this.sendPrefixPanel({
message,
event,
threadsData
});
}
};