goat
command
spy
Show user info card
0
views
0
likes
0
installs
Aliases: spy
raw source
const { createCanvas, loadImage } = require("canvas");
const axios = require("axios");
const fs = require("fs");
const path = require("path");
const moment = require("moment");
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function getRandomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
const numberNames = [
"", "Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion",
"Sextillion", "Septillion", "Octillion", "Nonillion", "Decillion", "Undecillion",
"Duodecillion", "Tredecillion", "Quattuordecillion", "Quindecillion", "Sexdecillion",
"Septendecillion", "Octodecillion", "Novemdecillion", "Vigintillion", "Unvigintillion",
"Duovigintillion", "Tresvigintillion", "Quattuorvigintillion", "Quinvigintillion",
"Sesvigintillion", "Septemvigintillion", "Octovigintillion", "Novemvigintillion",
"Trigintillion", "Untrigintillion", "Duotrigintillion", "Googol", "Googolplex",
"Centillion", "Uncentillion", "Duocentillion", "Trecentillion", "Quattuorcentillion",
"Quincentillion", "Sexcentillion", "Septencentillion", "Octocentillion",
"Novemcentillion", "Quattuordecillion", "Quindecillion", "Sexdecillion",
"Septendecillion", "Octodecillion", "Novemdecillion", "Vigintillion",
"Unvigintillion", "Duovigintillion", "Tresvigintillion", "Quattuorvigintillion",
"Quinvigintillion", "Sesvigintillion", "Septemvigintillion", "Octovigintillion",
"Novemvigintillion", "Trigintillion", "Untrigintillion", "Duotrigintillion",
"Tretrigintillion", "Quattuortrigintillion", "Quintrigintillion", "Sestrigintillion",
"Septentrigintillion", "Octotrigintillion", "Novemtrigintillion", "Quadragintillion",
"Unquadragintillion", "Duoquadragintillion", "Trequadragintillion",
"Quattuorquadragintillion", "Quinquadragintillion", "Sexquadragintillion",
"Septenquadragintillion", "Octoquadragintillion", "Novemquadragintillion",
"Quinquagintillion", "Unquinquagintillion", "Duoquinquagintillion",
"Trequinquagintillion", "Quattuorquinquagintillion", "Quinquinquagintillion",
"Sexquinquagintillion", "Septenquinquagintillion", "Octoquinquagintillion",
"Novemquinquagintillion", "Sexagintillion", "Unsexagintillion", "Duosexagintillion",
"Tresexagintillion", "Quattuorsexagintillion", "Quinsexagintillion",
"Sexsexagintillion", "Septensexagintillion", "Octosexagintillion",
"Novemsexagintillion", "Septuagintillion", "Unseptuagintillion",
"Duoseptuagintillion", "Treseptuagintillion", "Quattuorseptuagintillion",
"Quinseptuagintillion", "Sexseptuagintillion", "Septenseptuagintillion",
"Octoseptuagintillion", "Novemseptuagintillion", "Octogintillion",
"Unoctogintillion", "Duoctogintillion", "Treoctogintillion", "Quattuoroctogintillion",
"Quinoctogintillion", "Sexoctogintillion", "Septemoctogintillion",
"Octooctogintillion", "Novemoctogintillion", "Nonagintillion", "Unnonagintillion",
"Duononagintillion", "Trenonagintillion", "Quattuornonagintillion",
"Quinnonagintillion", "Sexnonagintillion", "Septennonagintillion",
"Octononagintillion", "Novemnonagintillion", "Centillion"
];
function formatMoney(num) {
if (num === 0) return "0";
if (num < 1000) return num.toString();
const exp = Math.floor(Math.log(num) / Math.log(1000));
if (exp >= numberNames.length) return "∞Infinity";
const value = num / Math.pow(1000, exp);
const rounded = Math.round(value * 100) / 100;
return `${rounded} ${numberNames[exp]}`;
}
function expToLevel(exp, deltaNext = 5) {
return Math.floor((1 + Math.sqrt(1 + 8 * exp / deltaNext)) / 2);
}
function levelToExp(level, deltaNext = 5) {
return Math.floor(((Math.pow(level, 2) - level) * deltaNext) / 2);
}
module.exports = {
config: {
name: "spy",
aliases: ["spy"],
version: "2.0",
author: "Rômeo",
countDown: 5,
shortDescription: { en: "Show user info card" },
longDescription: { en: "Generate a canvas image showing user stats" },
category: "info"
},
onStart: async function ({ event, message, usersData, args, api, threadsData }) {
let avatarUrl;
const uid1 = event.senderID;
const uid2 = Object.keys(event.mentions)[0];
let uid;
if (args[0]) {
if (/^\d+$/.test(args[0])) {
uid = args[0];
} else {
const match = args[0].match(/profile\.php\?id=(\d+)/);
if (match) {
uid = match[1];
}
}
}
if (!uid) {
uid = event.type === "message_reply" ? event.messageReply.senderID : uid2 || uid1;
}
avatarUrl = await usersData.getAvatarUrl(uid);
const userData = await usersData.get(uid);
const allUsers = await usersData.getAll();
const threadID = event.threadID;
const threadData = await threadsData.get(threadID);
const memberData = threadData.members.find(member => member.userID === uid);
const messages = memberData ? memberData.count || 0 : 0;
let username;
try {
const userInfo = await api.getUserInfo(uid);
username = userInfo[uid]?.vanity || userInfo[uid]?.name || "Not set";
} catch (e) {
username = userData.name || "Not set";
}
let genderText;
switch (userData.gender) {
case 1:
genderText = "Female"; break;
case 2:
genderText = "Male"; break;
default:
genderText = "Unknown";
}
const deltaNext = 5;
const exp = userData.exp || 0;
const levelUser = expToLevel(exp, deltaNext);
const expCurrentLevel = levelToExp(levelUser, deltaNext);
const expNextLevel = levelToExp(levelUser + 1, deltaNext);
const expProgress = exp - expCurrentLevel;
const expForNextLevel = expNextLevel - expCurrentLevel;
const percentage = Math.floor((expProgress / expForNextLevel) * 100);
const usersWithExp = allUsers.filter(u => typeof u.exp === "number").sort((a, b) => b.exp - a.exp);
const expRank = usersWithExp.findIndex(u => u.userID === uid) + 1;
const usersWithMoney = allUsers.filter(u => typeof u.money === "number").sort((a, b) => b.money - a.money);
const moneyRank = usersWithMoney.findIndex(u => u.userID === uid) + 1;
const name = userData.name || "Unknown";
const money = userData.money || 0;
const avatarBuffer = (await axios.get(avatarUrl, { responseType: "arraybuffer" })).data;
const avatar = await loadImage(avatarBuffer);
const canvas = createCanvas(1366, 768);
const ctx = canvas.getContext("2d");
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, "#0f0f1c");
gradient.addColorStop(1, "#1a1a2e");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < 150; i++) {
ctx.fillStyle = "white";
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const radius = Math.random() * 1.5;
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.fill();
}
// 🔥 Random Color
const randomColor = getRandomColor();
// Border
ctx.strokeStyle = randomColor;
ctx.lineWidth = 10;
ctx.strokeRect(5, 5, canvas.width - 10, canvas.height - 10);
// Avatar neon circle
ctx.save();
ctx.beginPath();
ctx.arc(683, 130, 90, 0, Math.PI * 2, true);
ctx.shadowColor = randomColor;
ctx.shadowBlur = 40;
ctx.strokeStyle = randomColor;
ctx.lineWidth = 6;
ctx.stroke();
ctx.restore();
// Draw Avatar
ctx.save();
ctx.beginPath();
ctx.arc(683, 130, 80, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
ctx.drawImage(avatar, 603, 50, 160, 160);
ctx.restore();
ctx.font = "bold 50px Arial";
ctx.textAlign = "center";
// Neon glow with stroke
ctx.save();
ctx.shadowColor = randomColor;
ctx.shadowBlur = 30;
ctx.strokeStyle = randomColor;
ctx.lineWidth = 4;
ctx.strokeText(name, 683, 280); // Stroke with neon
ctx.fillStyle = "#FFFFFF";
ctx.fillText(name, 683, 280); // Fill text
ctx.restore();
ctx.font = "bold 30px Arial";
ctx.textAlign = "left";
const infoLines = [
`🆔 User ID: ${uid}`,
`✏️ Nickname: ${name}`,
` Gender: ${genderText}`,
`🌐 Username: ${username}`,
`* Level: ${levelUser}`,
`⚡ Exp: ${exp}`,
`💰 Money: $${formatMoney(money)}`,
`💬 Messages: ${formatNumber(messages)}`,
`🏆 EXP Rank: #${expRank}`,
`💸 Money Rank: #${moneyRank}`
];
const leftX = 200;
const rightX = 800;
const baseY = 350;
const gap = 50;
for (let i = 0; i < 5; i++) {
ctx.fillText(infoLines[i], leftX, baseY + (i * gap));
}
for (let i = 5; i < 10; i++) {
ctx.fillText(infoLines[i], rightX, baseY + ((i - 5) * gap));
}
ctx.font = "bold 24px Arial";
ctx.fillStyle = "#FF6688";
ctx.textAlign = "center";
ctx.fillText(`Last Update: ${moment().format("YYYY-MM-DD HH:mm:ss")}`, canvas.width / 2, 740);
const tmpPath = path.join(__dirname, "tmp");
if (!fs.existsSync(tmpPath)) fs.mkdirSync(tmpPath);
const imagePath = path.join(tmpPath, `${uid}_info.png`);
fs.writeFileSync(imagePath, canvas.toBuffer());
message.reply({
body: "Here's your profile card:",
attachment: fs.createReadStream(imagePath),
}, () => fs.unlinkSync(imagePath));
}
};