← back to browse
goat command

leaderboard

Top 10 richest users

0
views
0
likes
0
installs

Aliases: lb, top

raw source
const fs = require("fs-extra");
const path = require("path");
const { createCanvas, loadImage } = require("canvas");
const axios = require("axios");

module.exports.config = {
  name: "leaderboard",
  aliases: ["lb", "top"],
  version: "6.0",
  author: "MOHAMMAD AKASH",
  countDown: 10,
  role: 0,
  shortDescription: "Top 10 richest users",
  category: "economy"
};

function formatBalance(num) {
  if (num >= 1e9) return (num / 1e9).toFixed(1) + "B";
  if (num >= 1e6) return (num / 1e6).toFixed(1) + "M";
  if (num >= 1e3) return (num / 1e3).toFixed(1) + "K";
  return String(num);
}

function roundRect(ctx, x, y, w, h, r, fill = false, stroke = false) {
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.quadraticCurveTo(x + w, y, x + w, y + r);
  ctx.lineTo(x + w, y + h - r);
  ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
  ctx.lineTo(x + r, y + h);
  ctx.quadraticCurveTo(x, y + h, x, y + h - r);
  ctx.lineTo(x, y + r);
  ctx.quadraticCurveTo(x, y, x + r, y);
  ctx.closePath();
  if (fill) ctx.fill();
  if (stroke) ctx.stroke();
}

async function loadAvatar(uid, cacheDir) {
  const tmpPath = path.join(cacheDir, `av_${uid}_${Date.now()}.png`);
  try {
    const imageUrl = `https://graph.facebook.com/${uid}/picture?height=200&width=200&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`;
    const response = await axios.get(imageUrl, { responseType: "arraybuffer" });
    await fs.writeFile(tmpPath, response.data);
    const img = await loadImage(tmpPath);
    await fs.remove(tmpPath);
    return img;
  } catch (e) {
    if (await fs.pathExists(tmpPath)) await fs.remove(tmpPath);
    return null;
  }
}

function drawAvatar(ctx, avatar, name, ax, ay, size, isTop3) {
  ctx.save();
  ctx.beginPath();
  ctx.arc(ax + size / 2, ay + size / 2, size / 2, 0, Math.PI * 2);
  ctx.clip();

  if (avatar) {
    ctx.drawImage(avatar, ax, ay, size, size);
  } else {
    const colors = ["#1565c0", "#6a1b9a", "#00695c", "#bf360c", "#4e342e", "#37474f"];
    ctx.fillStyle = colors[name.charCodeAt(0) % colors.length];
    ctx.fillRect(ax, ay, size, size);
    ctx.font = `bold ${Math.floor(size * 0.45)}px Arial`;
    ctx.fillStyle = "#ffffff";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillText((name || "?")[0].toUpperCase(), ax + size / 2, ay + size / 2 + 2);
  }

  ctx.restore();
  ctx.strokeStyle = isTop3 ? "#ffd700" : "rgba(255,255,255,0.3)";
  ctx.lineWidth = isTop3 ? 2.5 : 1.5;
  ctx.beginPath();
  ctx.arc(ax + size / 2, ay + size / 2, size / 2 + 2, 0, Math.PI * 2);
  ctx.stroke();
}

module.exports.onStart = async function ({ api, event, usersData }) {
  const { threadID, messageID } = event;

  const allUsers = await usersData.getAll();
  const sorted = Object.entries(allUsers)
    .map(([uid, data]) => ({
      uid,
      name: data.name || "Unknown",
      money: data?.data?.money ?? 0
    }))
    .sort((a, b) => b.money - a.money)
    .slice(0, 10);

  const cacheDir = path.join(__dirname, "cache");
  await fs.ensureDir(cacheDir);

  const avatars = [];
  for (const user of sorted) {
    const img = await loadAvatar(user.uid, cacheDir);
    avatars.push(img);
  }

  const width = 800;
  const rowH = 72;
  const headerH = 130;
  const footerH = 50;
  const height = headerH + rowH * sorted.length + footerH;

  const canvas = createCanvas(width, height);
  const ctx = canvas.getContext("2d");

  const bgGrad = ctx.createLinearGradient(0, 0, width, height);
  bgGrad.addColorStop(0, "#0a2a4a");
  bgGrad.addColorStop(1, "#0f4c81");
  ctx.fillStyle = bgGrad;
  roundRect(ctx, 0, 0, width, height, 20, true);

  ctx.fillStyle = "rgba(255,255,255,0.04)";
  for (let i = 0; i < 5; i++) {
    ctx.beginPath();
    ctx.arc(width - 40 + i * 25, 30 + i * 20, 90 + i * 35, 0, Math.PI * 2);
    ctx.fill();
  }

  ctx.textAlign = "center";
  ctx.font = "bold 38px Arial";
  ctx.fillStyle = "#ffffff";
  ctx.fillText("๐Ÿ†  LEADERBOARD", width / 2, 55);

  ctx.font = "18px Arial";
  ctx.fillStyle = "rgba(255,255,255,0.6)";
  ctx.fillText("GOAT NATIONAL BANK โ€” TOP 10", width / 2, 85);

  ctx.strokeStyle = "rgba(255,255,255,0.15)";
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(40, 105);
  ctx.lineTo(width - 40, 105);
  ctx.stroke();

  const medals = ["๐Ÿฅ‡", "๐Ÿฅˆ", "๐Ÿฅ‰"];
  const avatarSize = 46;

  for (let i = 0; i < sorted.length; i++) {
    const user = sorted[i];
    const avatar = avatars[i];
    const y = headerH + i * rowH;
    const isTop3 = i < 3;

    if (isTop3) {
      const rowGrad = ctx.createLinearGradient(30, y, width - 30, y);
      rowGrad.addColorStop(0, "rgba(255,215,0,0.12)");
      rowGrad.addColorStop(1, "rgba(255,215,0,0.02)");
      ctx.fillStyle = rowGrad;
    } else {
      ctx.fillStyle = i % 2 === 0 ? "rgba(255,255,255,0.05)" : "rgba(255,255,255,0.02)";
    }
    roundRect(ctx, 30, y + 6, width - 60, rowH - 10, 12, true);

    ctx.textAlign = "center";
    ctx.textBaseline = "alphabetic";
    ctx.font = isTop3 ? "bold 26px Arial" : "bold 20px Arial";
    ctx.fillStyle = isTop3 ? "#ffd700" : "rgba(255,255,255,0.5)";
    ctx.fillText(isTop3 ? medals[i] : `#${i + 1}`, 72, y + rowH / 2 + 8);

    const ax = 100;
    const ay = y + rowH / 2 - avatarSize / 2;
    drawAvatar(ctx, avatar, user.name, ax, ay, avatarSize, isTop3);

    ctx.textAlign = "left";
    ctx.textBaseline = "alphabetic";
    let displayName = user.name;
    ctx.font = isTop3 ? "bold 22px Arial" : "bold 19px Arial";
    ctx.fillStyle = "#ffffff";
    while (ctx.measureText(displayName).width > 390 && displayName.length > 1) {
      displayName = displayName.slice(0, -1);
    }
    if (displayName !== user.name) displayName += "โ€ฆ";
    ctx.fillText(displayName, 162, y + rowH / 2 + 8);

    ctx.textAlign = "right";
    ctx.font = isTop3 ? "bold 22px Arial" : "bold 19px Arial";
    ctx.fillStyle = isTop3 ? "#ffd700" : "#4fc3f7";
    ctx.fillText("$" + formatBalance(user.money), width - 50, y + rowH / 2 + 8);
  }

  ctx.textAlign = "center";
  ctx.font = "15px Arial";
  ctx.fillStyle = "rgba(255,255,255,0.3)";
  ctx.fillText("GOAT BOT  โ€ข  Economy System", width / 2, height - 18);

  const filePath = path.join(cacheDir, `leaderboard_${Date.now()}.png`);
  await fs.writeFile(filePath, canvas.toBuffer("image/png"));

  await api.sendMessage({ attachment: fs.createReadStream(filePath) }, threadID, messageID);
  setTimeout(() => fs.remove(filePath), 10000);
};

View raw file