goat
command
leave
Group Cover BG & Dynamic Leave/Kick Card
0
views
0
likes
0
installs
raw source
const { createCanvas, loadImage } = require("canvas");
const fs = require("fs-extra");
const path = require("path");
const moment = require("moment-timezone");
module.exports = {
config: {
name: "leave",
version: "7.0.0",
author: "Protik Shah",
category: "events",
description: "Group Cover BG & Dynamic Leave/Kick Card"
},
onStart: async function ({ api, event }) {
if (event.logMessageType !== "log:unsubscribe") return;
const { threadID, logMessageData, author } = event;
const leftParticipantFbId = logMessageData.leftParticipantFbId;
if (leftParticipantFbId === api.getCurrentUserID()) return;
try {
const threadInfo = await api.getThreadInfo(threadID);
const threadName = threadInfo.threadName || "Diablo Realm";
const memberCount = threadInfo.participantIDs.length;
const groupIconUrl = threadInfo.imageSrc || "https://i.ibb.co/L5k6NvZ/bg2.jpg";
const userInfo = await api.getUserInfo(leftParticipantFbId);
const userName = userInfo[leftParticipantFbId]?.name || "Facebook user";
// Detect Self Leave vs Kicked by Admin
const isKicked = author && author !== leftParticipantFbId;
const mainHeader = isKicked ? "MEMBER KICKED!" : "GOODBYE MEMBER!";
const subTag = isKicked ? "๐ซ MEMBER REMOVED ๐ซ" : "๐ฅ MEMBER DEPARTED ๐ฅ";
const statusMsg = isKicked ? "Removed from group by Admin." : "Has left the group chat.";
const timeNow = moment().tz("Asia/Dhaka").format("hh:mm A | DD MMM YYYY");
const canvas = createCanvas(1000, 500);
const ctx = canvas.getContext("2d");
// 1. Group Cover Background with Blur
try {
const bgImg = await loadImage(groupIconUrl);
ctx.filter = "blur(12px)";
ctx.drawImage(bgImg, -20, -20, canvas.width + 40, canvas.height + 40);
ctx.filter = "none";
} catch (e) {
ctx.fillStyle = "#140508";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// Dark Overlay
ctx.fillStyle = "rgba(20, 5, 8, 0.88)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Divider Line
ctx.strokeStyle = "rgba(255, 42, 69, 0.25)";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(420, 0);
ctx.lineTo(420, 500);
ctx.stroke();
// 2. Avatar Rendering
const targetAvatarUrl = `https://graph.facebook.com/${leftParticipantFbId}/picture?height=500&width=500&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`;
if (!isKicked) {
// Self Leave: Single Centered Avatar
try {
const targetImg = await loadImage(targetAvatarUrl);
ctx.save();
ctx.shadowColor = "#ff2a45";
ctx.shadowBlur = 25;
ctx.beginPath();
ctx.arc(210, 200, 85, 0, Math.PI * 2);
ctx.clip();
ctx.drawImage(targetImg, 125, 115, 170, 170);
ctx.restore();
ctx.strokeStyle = "#ff2a45";
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(210, 200, 85, 0, Math.PI * 2);
ctx.stroke();
} catch (e) {}
} else {
// Kicked: Dual Avatar (Admin + Kicked User)
const adminAvatarUrl = `https://graph.facebook.com/${author}/picture?height=500&width=500&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`;
try {
const adminImg = await loadImage(adminAvatarUrl);
ctx.save();
ctx.beginPath();
ctx.arc(150, 200, 60, 0, Math.PI * 2);
ctx.clip();
ctx.drawImage(adminImg, 90, 140, 120, 120);
ctx.restore();
ctx.strokeStyle = "#ffffff";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(150, 200, 60, 0, Math.PI * 2);
ctx.stroke();
} catch (e) {}
try {
const targetImg = await loadImage(targetAvatarUrl);
ctx.save();
ctx.shadowColor = "#ff2a45";
ctx.shadowBlur = 20;
ctx.beginPath();
ctx.arc(260, 200, 70, 0, Math.PI * 2);
ctx.clip();
ctx.drawImage(targetImg, 190, 130, 140, 140);
ctx.restore();
ctx.strokeStyle = "#ff2a45";
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(260, 200, 70, 0, Math.PI * 2);
ctx.stroke();
} catch (e) {}
}
// Sub Text
ctx.fillStyle = "#ff2a45";
ctx.font = "bold 18px 'Segoe UI', Sans-serif";
ctx.textAlign = "center";
ctx.fillText(subTag, 210, 350);
// 3. Right Panel Content
ctx.textAlign = "left";
ctx.fillStyle = "#ffffff";
ctx.font = "900 38px 'Segoe UI', Sans-serif";
ctx.fillText(mainHeader, 460, 110);
ctx.fillStyle = "#ff2a45";
ctx.font = "bold 28px 'Segoe UI', Sans-serif";
ctx.fillText(userName, 460, 160);
// Strip 1: Action Status
ctx.fillStyle = "rgba(255, 42, 69, 0.15)";
ctx.beginPath();
ctx.roundRect(460, 195, 480, 50, 12);
ctx.fill();
ctx.fillStyle = "#ffffff";
ctx.font = "18px 'Segoe UI', Sans-serif";
ctx.fillText(statusMsg, 480, 227);
// Strip 2: Group Name
ctx.fillStyle = "rgba(255, 42, 69, 0.15)";
ctx.beginPath();
ctx.roundRect(460, 265, 480, 50, 12);
ctx.fill();
ctx.fillStyle = "#ff2a45";
ctx.font = "bold 18px 'Segoe UI', Sans-serif";
ctx.fillText(`GROUP: ${threadName}`, 480, 297);
// Badges
ctx.fillStyle = "#ff2a45";
ctx.beginPath();
ctx.roundRect(460, 355, 210, 48, 12);
ctx.fill();
ctx.fillStyle = "#ffffff";
ctx.font = "bold 18px 'Segoe UI', Sans-serif";
ctx.fillText(`REMAINING: ${memberCount}`, 480, 385);
ctx.fillStyle = "#221115";
ctx.beginPath();
ctx.roundRect(690, 355, 250, 48, 12);
ctx.fill();
ctx.fillStyle = "#a0aec0";
ctx.font = "15px 'Segoe UI', Sans-serif";
ctx.fillText(timeNow, 705, 384);
const cardPath = path.join(__dirname, `cache_leave_${leftParticipantFbId}.png`);
fs.writeFileSync(cardPath, canvas.toBuffer("image/png"));
api.sendMessage(
{
body: isKicked ? `๐ซ ${userName} was removed from ${threadName}.` : `๐ ${userName} has left ${threadName}.`,
attachment: fs.createReadStream(cardPath)
},
threadID,
() => {
if (fs.existsSync(cardPath)) fs.unlinkSync(cardPath);
}
);
} catch (err) {
console.error("Leave Error:", err);
}
}
};