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); } } };