mirai
command
welcome
No description
0
views
0
likes
0
installs
raw source
const { getTime, drive } = global.utils;
const { nickNameBot } = global.GoatBot.config;
const { createCanvas, loadImage, registerFont } = require("@napi-rs/canvas");
const fs = require("fs-extra");
const path = require("path");
const axios = require("axios");
module.exports = {
config: {
name: "welcome",
version: "4.0",
author: "Nagi-X-Ajmaul",
category: "events"
},
langs: {
en: {
session1: "morning",
session2: "noon",
session3: "afternoon",
session4: "evening",
defaultWelcomeMessage: "𝐖𝐄𝐋𝐂𝐎𝐌𝐄 {userTag}",
botAddedMessage:
"━━━━━━━━━━━━━━━━━━━\n🤖 ᴛʜᴀɴᴋ ʏᴏᴜ ғᴏʀ ᴀᴅᴅɪɴɢ ᴍᴇ ᴛᴏ ᴛʜᴇ ɢʀᴏᴜᴘ! 💖\n\n⚙️ ʙᴏᴛ ᴘʀᴇꜰɪx : /\n📜 ᴛʏᴘᴇ /help ᴛᴏ sᴇᴇ ᴀʟʟ ᴄᴏᴍᴍᴀɴᴅs\n\n✨ ʟᴇᴛ's ᴍᴀᴋᴇ ᴛʜɪs ɢʀᴏᴜᴘ ᴇᴠᴇɴ ᴍᴏʀᴇ ꜰᴜɴ ᴛᴏɢᴇᴛʜᴇʀ! 😄\n━━━━━━━━━━━━━━━━━━━"
}
},
onStart: async ({ threadsData, message, event, api, usersData, getLang }) => {
if (event.logMessageType !== "log:subscribe") return;
const { threadID } = event;
const threadData = await threadsData.get(threadID);
if (!threadData.settings.sendWelcomeMessage) return;
const addedMembers = event.logMessageData.addedParticipants;
const threadName = threadData.threadName || "our group";
const prefix = global.utils.getPrefix(threadID);
const inviterID = event.author;
for (const user of addedMembers) {
const userID = user.userFbId;
const botID = api.getCurrentUserID();
// ✅ যদি বটকে অ্যাড করা হয়
if (userID == botID) {
if (nickNameBot)
await api.changeNickname(nickNameBot, threadID, botID);
return message.send(getLang("botAddedMessage", prefix));
}
// ✅ যদি নতুন ইউজার হয়
const userName = user.fullName;
const userTag = `@${userName}`;
const inviterName = await usersData.getName(inviterID);
const memberCount = event.participantIDs.length;
let { welcomeMessage = getLang("defaultWelcomeMessage") } = threadData.data;
welcomeMessage = welcomeMessage
.replace(/\{userName\}/g, userName)
.replace(/\{userTag\}/g, userTag)
.replace(/\{threadName\}/g, threadName)
.replace(/\{memberCount\}/g, memberCount)
.replace(/\{inviterName\}/g, inviterName);
// Welcome Image Card তৈরি
let welcomeImagePath;
try {
welcomeImagePath = await createWelcomeCard({
userName,
userTag,
threadName,
memberCount,
inviterName,
newUserID: userID,
inviterID: inviterID,
threadID: threadID,
api: api
});
} catch (err) {
console.error("Welcome image creation failed:", err);
welcomeImagePath = null;
}
const form = {
body: welcomeMessage,
mentions: [{ tag: userName, id: userID }]
};
// ✅ Welcome Image Card অ্যাটাচ
if (welcomeImagePath && fs.existsSync(welcomeImagePath)) {
form.attachment = fs.createReadStream(welcomeImagePath);
} else if (threadData.data.welcomeAttachment) {
// পূর্বের অ্যাটাচমেন্ট সিস্টেম
const files = threadData.data.welcomeAttachment;
const attachments = files.reduce((acc, file) => {
acc.push(drive.getFile(file, "stream"));
return acc;
}, []);
form.attachment = (await Promise.allSettled(attachments))
.filter(({ status }) => status == "fulfilled")
.map(({ value }) => value);
}
message.send(form);
// Temporary image file delete
if (welcomeImagePath && fs.existsSync(welcomeImagePath)) {
setTimeout(() => fs.unlinkSync(welcomeImagePath), 5000);
}
}
}
};
// ✅ Graph API Access Token (আপনার pp কমান্ড থেকে)
const ACCESS_TOKEN = "6628568379%7Cc1e620fa708a1d5696fb991c1bde5662";
async function downloadHighQualityProfile(userID) {
try {
// Graph API দিয়ে হাই রেজোল্যুশন ইমেজ (500x500)
const highResUrl = `https://graph.facebook.com/${userID}/picture?width=500&height=500&access_token=${ACCESS_TOKEN}`;
const response = await axios({
method: 'GET',
url: highResUrl,
responseType: 'arraybuffer',
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
return Buffer.from(response.data, 'binary');
} catch (error) {
console.log(`Graph API failed for user ${userID}:`, error.message);
return null;
}
}
async function downloadImage(url) {
try {
const response = await axios({
method: 'GET',
url: url,
responseType: 'arraybuffer',
timeout: 10000
});
return Buffer.from(response.data, 'binary');
} catch (error) {
console.log("Image download failed:", error.message);
return null;
}
}
async function getGroupImage(threadID, api) {
try {
const threadInfo = await api.getThreadInfo(threadID);
if (threadInfo.imageSrc) {
const response = await axios({
method: 'GET',
url: threadInfo.imageSrc,
responseType: 'arraybuffer',
timeout: 10000
});
return Buffer.from(response.data, 'binary');
}
} catch (error) {
console.log("Group image download failed:", error.message);
}
return null;
}
async function createWelcomeCard({ userName, userTag, threadName, memberCount, inviterName, newUserID, inviterID, threadID, api }) {
const width = 1200;
const height = 675;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
// ✅ Elegant Dark Background
const gradient = ctx.createLinearGradient(0, 0, width, height);
gradient.addColorStop(0, '#0c0c0c');
gradient.addColorStop(0.3, '#1a1a2e');
gradient.addColorStop(0.7, '#16213e');
gradient.addColorStop(1, '#0f3460');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// ✅ Background Pattern (Subtle)
ctx.fillStyle = 'rgba(255, 255, 255, 0.03)';
for (let i = 0; i < 100; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const size = Math.random() * 3 + 1;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
// ✅ Top decorative line
ctx.strokeStyle = 'rgba(255, 215, 0, 0.4)';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(width * 0.1, 90);
ctx.lineTo(width * 0.9, 90);
ctx.stroke();
// ✅ Main Title - Welcome To
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 60px "Segoe UI", Arial';
ctx.textAlign = 'center';
ctx.shadowColor = 'rgba(255, 215, 0, 0.5)';
ctx.shadowBlur = 12;
ctx.fillText('Welcome To', width / 2, 160);
ctx.shadowBlur = 0;
// ✅ Top Section - User & Inviter Profiles
const topY = 250;
const profileSize = 70;
const leftX = width * 0.25;
const rightX = width * 0.75;
// ✅ Left Side - New User Section
// New User Profile Frame (Green)
ctx.beginPath();
ctx.arc(leftX, topY, profileSize + 8, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(46, 204, 113, 0.15)';
ctx.fill();
ctx.strokeStyle = '#2ecc71';
ctx.lineWidth = 4;
ctx.stroke();
// Load new user profile with HIGH QUALITY Graph API
let newUserImage = null;
if (newUserID) {
try {
// প্রথমে Graph API দিয়ে চেষ্টা করবে
const imageBuffer = await downloadHighQualityProfile(newUserID);
if (imageBuffer) {
newUserImage = await loadImage(imageBuffer);
} else {
// Fallback: FB API থাম্বনেইল
try {
const profilePic = await api.getUserInfo([newUserID]);
if (profilePic[newUserID] && profilePic[newUserID].thumbSrc) {
const fallbackBuffer = await downloadImage(profilePic[newUserID].thumbSrc);
if (fallbackBuffer) {
newUserImage = await loadImage(fallbackBuffer);
}
}
} catch (fallbackErr) {
console.log("Fallback also failed for new user:", fallbackErr.message);
}
}
} catch (err) {
console.log("New user image load failed:", err.message);
}
}
if (newUserImage) {
ctx.save();
ctx.beginPath();
ctx.arc(leftX, topY, profileSize, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
// HQ ইমেজের জন্য স্মুথ ড্রয়িং
ctx.drawImage(
newUserImage,
leftX - profileSize,
topY - profileSize,
profileSize * 2,
profileSize * 2
);
ctx.restore();
} else {
// Default avatar for new user
ctx.fillStyle = '#333344';
ctx.beginPath();
ctx.arc(leftX, topY, profileSize, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 45px Arial';
ctx.textAlign = 'center';
ctx.fillText('👤', leftX, topY + 15);
}
// "NEW USER" Label
ctx.fillStyle = '#2ecc71';
ctx.font = 'bold 24px "Segoe UI", Arial';
ctx.fillText('NEW USER', leftX, topY + profileSize + 40);
// New User Name (with text wrapping if too long)
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 28px "Segoe UI", Arial';
// Truncate long names
let displayName = userName;
const maxNameLength = 18;
if (userName.length > maxNameLength) {
displayName = userName.substring(0, maxNameLength) + '...';
}
ctx.fillText(displayName, leftX, topY + profileSize + 75);
// ✅ Right Side - Added By Section
// Added By Profile Frame (Blue)
ctx.beginPath();
ctx.arc(rightX, topY, profileSize + 8, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(52, 152, 219, 0.15)';
ctx.fill();
ctx.strokeStyle = '#3498db';
ctx.lineWidth = 4;
ctx.stroke();
// Load inviter profile with HIGH QUALITY Graph API
let inviterImage = null;
if (inviterID) {
try {
// প্রথমে Graph API দিয়ে চেষ্টা করবে
const imageBuffer = await downloadHighQualityProfile(inviterID);
if (imageBuffer) {
inviterImage = await loadImage(imageBuffer);
} else {
// Fallback: FB API থাম্বনেইল
try {
const profilePic = await api.getUserInfo([inviterID]);
if (profilePic[inviterID] && profilePic[inviterID].thumbSrc) {
const fallbackBuffer = await downloadImage(profilePic[inviterID].thumbSrc);
if (fallbackBuffer) {
inviterImage = await loadImage(fallbackBuffer);
}
}
} catch (fallbackErr) {
console.log("Fallback also failed for inviter:", fallbackErr.message);
}
}
} catch (err) {
console.log("Inviter image load failed:", err.message);
}
}
if (inviterImage) {
ctx.save();
ctx.beginPath();
ctx.arc(rightX, topY, profileSize, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
// HQ ইমেজের জন্য স্মুথ ড্রয়িং
ctx.drawImage(
inviterImage,
rightX - profileSize,
topY - profileSize,
profileSize * 2,
profileSize * 2
);
ctx.restore();
} else {
// Default avatar for inviter
ctx.fillStyle = '#333344';
ctx.beginPath();
ctx.arc(rightX, topY, profileSize, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 45px Arial';
ctx.textAlign = 'center';
ctx.fillText('👤', rightX, topY + 15);
}
// "ADDED BY" Label
ctx.fillStyle = '#3498db';
ctx.font = 'bold 24px "Segoe UI", Arial';
ctx.fillText('ADDED BY', rightX, topY + profileSize + 40);
// Added By Name (with text wrapping)
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 28px "Segoe UI", Arial';
// Truncate long names
let displayInviterName = inviterName;
if (inviterName.length > maxNameLength) {
displayInviterName = inviterName.substring(0, maxNameLength) + '...';
}
ctx.fillText(displayInviterName, rightX, topY + profileSize + 75);
// ✅ Connecting Lines with Arrow
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.lineWidth = 2;
ctx.setLineDash([8, 4]);
// Connecting line from New User to Added By
ctx.beginPath();
ctx.moveTo(leftX + profileSize + 10, topY);
ctx.lineTo(rightX - profileSize - 10, topY);
ctx.stroke();
ctx.setLineDash([]);
// Arrow pointing from Added By side (indicating direction)
ctx.fillStyle = '#3498db';
ctx.beginPath();
ctx.moveTo(rightX - profileSize - 25, topY);
ctx.lineTo(rightX - profileSize - 40, topY - 10);
ctx.lineTo(rightX - profileSize - 40, topY + 10);
ctx.closePath();
ctx.fill();
// ✅ Middle Section - Group Info
const groupY = 420;
const centerX = width / 2;
const groupImageSize = 80;
// Group Image Frame
ctx.beginPath();
ctx.arc(centerX, groupY, groupImageSize + 10, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(0, 200, 255, 0.15)';
ctx.fill();
ctx.strokeStyle = '#00c8ff';
ctx.lineWidth = 4;
ctx.stroke();
// Load group image
let groupImage = null;
if (threadID) {
try {
const imageBuffer = await getGroupImage(threadID, api);
if (imageBuffer) {
groupImage = await loadImage(imageBuffer);
}
} catch (err) {
console.log("Group image load failed:", err.message);
}
}
if (groupImage) {
ctx.save();
ctx.beginPath();
ctx.arc(centerX, groupY, groupImageSize, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
ctx.drawImage(groupImage, centerX - groupImageSize, groupY - groupImageSize, groupImageSize * 2, groupImageSize * 2);
ctx.restore();
} else {
// Default group icon
ctx.fillStyle = '#2d3436';
ctx.beginPath();
ctx.arc(centerX, groupY, groupImageSize, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 60px Arial';
ctx.textAlign = 'center';
ctx.fillText('👥', centerX, groupY + 20);
}
// ✅ Group Name (Single Line with Auto Font Size Adjustment)
let displayGroupName = threadName;
const maxWidth = width * 0.8; // 80% of image width
// Start with larger font size
let fontSize = 32;
let actualWidth;
// Calculate text width and reduce font size if needed
do {
ctx.font = `bold ${fontSize}px "Segoe UI", Arial`;
actualWidth = ctx.measureText(displayGroupName).width;
if (actualWidth > maxWidth && fontSize > 20) {
fontSize -= 2;
} else {
break;
}
} while (actualWidth > maxWidth && fontSize > 20);
// If still too long, truncate with ellipsis
if (actualWidth > maxWidth) {
let truncatedName = threadName;
while (ctx.measureText(truncatedName + '...').width > maxWidth && truncatedName.length > 1) {
truncatedName = truncatedName.substring(0, truncatedName.length - 1);
}
displayGroupName = truncatedName + '...';
}
// Draw group name
ctx.fillStyle = '#ffffff';
ctx.font = `bold ${fontSize}px "Segoe UI", Arial`;
ctx.fillText(displayGroupName, centerX, groupY + groupImageSize + 50);
// ✅ Member Count Section
const memberY = 570;
const boxWidth = 500;
const boxHeight = 50;
const boxX = (width - boxWidth) / 2;
const boxY = memberY;
// Member Count Box Background
ctx.fillStyle = 'rgba(155, 89, 182, 0.2)';
ctx.fillRect(boxX, boxY, boxWidth, boxHeight);
// Member Count Box Border
ctx.strokeStyle = '#9b59b6';
ctx.lineWidth = 3;
ctx.strokeRect(boxX, boxY, boxWidth, boxHeight);
// Member Count Text (with ordinal suffix)
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 32px "Segoe UI", Arial';
let suffix = "th";
if (memberCount % 10 === 1 && memberCount % 100 !== 11) suffix = "st";
else if (memberCount % 10 === 2 && memberCount % 100 !== 12) suffix = "nd";
else if (memberCount % 10 === 3 && memberCount % 100 !== 13) suffix = "rd";
const memberText = `You are the ${memberCount}${suffix} Member`;
ctx.fillText(memberText, width / 2, boxY + 35);
// ✅ Separator Line between Group and Member Count
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(width * 0.2, memberY - 20);
ctx.lineTo(width * 0.8, memberY - 20);
ctx.stroke();
// ✅ Bottom decorative line
ctx.strokeStyle = 'rgba(255, 215, 0, 0.3)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(width * 0.1, height - 40);
ctx.lineTo(width * 0.9, height - 40);
ctx.stroke();
// ✅ Footer Text
ctx.fillStyle = '#aaaaaa';
ctx.font = '20px "Segoe UI", Arial';
ctx.fillText('Enjoy your stay in our community!', width / 2, height - 15);
// ✅ Border
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineWidth = 2;
ctx.strokeRect(10, 10, width - 20, height - 20);
// ✅ Save image
const tempPath = path.join(__dirname, `temp_welcome_${Date.now()}.png`);
const buffer = canvas.toBuffer('image/png');
await fs.writeFile(tempPath, buffer);
return tempPath;
}