goat
command
pair
No description
0
views
0
likes
0
installs
raw source
const axios = require("axios");
const fs = require("fs-extra");
const path = require("path");
let createCanvas, loadImage;
try {
const canvas = require("canvas");
createCanvas = canvas.createCanvas;
loadImage = canvas.loadImage;
} catch (e) {}
const BEST_FILE = path.join(__dirname, "cache", "best_match.json");
const CACHE_DIR = path.join(__dirname, "cache");
const TEMPLATES = [
{ url: "https://files.catbox.moe/xmsmrt.jpeg", maleSide: "left", left: { x: 0.22, y: 0.48, size: 0.26 }, right: { x: 0.72, y: 0.48, size: 0.26 } },
{ url: "https://files.catbox.moe/dkbxze.jpeg", maleSide: "left", left: { x: 0.28, y: 0.28, size: 0.24 }, right: { x: 0.68, y: 0.30, size: 0.24 } },
{ url: "https://files.catbox.moe/c5syq8.jpeg", maleSide: "right", left: { x: 0.25, y: 0.18, size: 0.22 }, right: { x: 0.68, y: 0.16, size: 0.22 } },
{ url: "https://files.catbox.moe/awasn6.jpeg", maleSide: "right", left: { x: 0.28, y: 0.35, size: 0.24 }, right: { x: 0.65, y: 0.38, size: 0.24 } },
{ url: "https://files.catbox.moe/voo30r.jpeg", maleSide: "right", left: { x: 0.22, y: 0.32, size: 0.22 }, right: { x: 0.68, y: 0.30, size: 0.22 } }
];
const RANDOM_GIFS = [
"https://files.catbox.moe/i9yxez.gif",
"https://files.catbox.moe/a3r48n.gif",
"https://files.catbox.moe/6lnz86.gif",
"https://files.catbox.moe/u3ip3u.gif",
"https://files.catbox.moe/ydl2aq.gif",
"https://files.catbox.moe/gp5ulj.gif"
];
const TITLES = [
"💘 Perfect Match",
"💞 Soulmates",
"✨ Destiny Pair",
"🌌 Cosmic Love",
"💓 Heart Sync",
"👑 Ultimate Couple",
"🔒 Love Locked",
"🌹 Made For Each Other"
];
function getBadge(p) {
if (p >= 95) return "🏆 LEGENDARY";
if (p >= 88) return "💯 PERFECT";
if (p >= 78) return "🔥 GREAT";
if (p >= 68) return "😊 GOOD";
return "🙂 NICE";
}
function makeCaption(percent, title) {
const list = [
`${title}\n\n💓 দুজনের মিল: ${percent}%`,
`${title}\n\n💘 Love Score: ${percent}%`,
`${title}\n\n✨ Compatibility: ${percent}%`
];
return list[Math.floor(Math.random() * list.length)];
}
async function loadAvatar(uid) {
if (!loadImage) return null;
const urls = [
`https://graph.facebook.com/${uid}/picture?width=512&height=512&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`,
`https://graph.facebook.com/${uid}/picture?type=large&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`,
`https://graph.facebook.com/${uid}/picture?width=512&height=512`,
`https://graph.facebook.com/${uid}/picture?type=large`
];
for (const url of urls) {
try {
const img = await loadImage(url);
if (img && img.width >= 80) return img;
} catch (e) {}
}
return null;
}
async function downloadBuffer(url) {
try {
const res = await axios.get(url, { responseType: "arraybuffer", timeout: 15000 });
return Buffer.from(res.data);
} catch (e) {
return null;
}
}
async function createTemplatePair(senderID, targetID, senderName, targetName, senderGender, percent) {
if (!createCanvas || !loadImage) return null;
try {
const tpl = TEMPLATES[Math.floor(Math.random() * TEMPLATES.length)];
const bg = await loadImage(tpl.url);
const W = bg.width;
const H = bg.height;
const canvas = createCanvas(W, H);
const ctx = canvas.getContext("2d");
ctx.drawImage(bg, 0, 0, W, H);
let leftID, rightID, leftName, rightName;
if (tpl.maleSide === "left") {
if (senderGender === "male") {
leftID = senderID; leftName = senderName;
rightID = targetID; rightName = targetName;
} else {
leftID = targetID; leftName = targetName;
rightID = senderID; rightName = senderName;
}
} else {
if (senderGender === "male") {
rightID = senderID; rightName = senderName;
leftID = targetID; leftName = targetName;
} else {
rightID = targetID; rightName = targetName;
leftID = senderID; leftName = senderName;
}
}
const leftImg = await loadAvatar(leftID);
const rightImg = await loadAvatar(rightID);
function drawCircle(img, x, y, size) {
if (!img) return;
const r = size / 2;
ctx.save();
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
ctx.drawImage(img, x - r, y - r, size, size);
ctx.restore();
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.strokeStyle = "#fff";
ctx.lineWidth = Math.max(4, size * 0.04);
ctx.stroke();
}
const ls = tpl.left.size * Math.min(W, H);
const rs = tpl.right.size * Math.min(W, H);
drawCircle(leftImg, tpl.left.x * W, tpl.left.y * H, ls);
drawCircle(rightImg, tpl.right.x * W, tpl.right.y * H, rs);
return canvas.toBuffer("image/png");
} catch (e) {
console.error("createTemplatePair:", e.message);
return null;
}
}
/**
* SAAN স্টাইল — getThreadInfo().userInfo থেকে এক কলেই gender
* ছেলে → মেয়ে, মেয়ে → ছেলে
*/
async function pickOppositePartner(api, threadID, senderID, botID) {
const thread = await api.getThreadInfo(threadID);
const users = thread.userInfo || [];
const me = users.find(u => String(u.id) === String(senderID));
let myGender = (me?.gender || "").toUpperCase(); // MALE / FEMALE
// userInfo তে gender না থাকলে fallback
if (!myGender || (myGender !== "MALE" && myGender !== "FEMALE")) {
try {
const info = await api.getUserInfo(senderID);
const g = info[senderID]?.gender;
if (g === 1 || g === "female" || g === "FEMALE") myGender = "FEMALE";
else if (g === 2 || g === "male" || g === "MALE") myGender = "MALE";
else myGender = "MALE";
} catch (e) {
myGender = "MALE";
}
}
let candidates = [];
if (myGender === "MALE") {
candidates = users.filter(
u => u.gender === "FEMALE" && String(u.id) !== String(senderID) && String(u.id) !== String(botID)
);
} else {
candidates = users.filter(
u => u.gender === "MALE" && String(u.id) !== String(senderID) && String(u.id) !== String(botID)
);
}
// অপর জেন্ডার না থাকলে যেকোনো মেম্বার
if (!candidates.length) {
candidates = users.filter(
u => String(u.id) !== String(senderID) && String(u.id) !== String(botID)
);
}
if (!candidates.length) return null;
const selected = candidates[Math.floor(Math.random() * candidates.length)];
return {
targetID: selected.id,
targetName: selected.name || "Partner",
senderGender: myGender === "FEMALE" ? "female" : "male",
users
};
}
module.exports = {
config: {
name: "pair",
version: "3.0.0",
author: "Banu_suna + SAAN logic",
countDown: 5,
role: 0,
description: {
en: "Find random couple with opposite gender (boy↔girl)",
bn: "ছেলে-মেয়ে মিলিয়ে random জুটি খোঁজো"
},
category: "fun",
guide: {
en: "{pn}\n{pn} @tag\n{pn} (reply)\n{pn} best\n{pn} gif",
bn: "{pn}\n{pn} @ট্যাগ\n{pn} (রিপ্লাই)\n{pn} best\n{pn} gif"
}
},
langs: {
en: {
waiting: "💘 Finding your perfect match...",
noMembers: "❌ | No suitable match found in this group!",
selfPair: "❌ | You cannot pair with yourself!",
noBest: "❌ | No best match recorded today yet.",
bestTitle: "🏆 Today's Best Match",
error: "❌ | Something went wrong. Try again."
},
bn: {
waiting: "💘 তোমার পারফেক্ট ম্যাচ খোঁজা হচ্ছে...",
noMembers: "❌ | গ্রুপে উপযুক্ত ম্যাচ পাওয়া যায়নি!",
selfPair: "❌ | নিজের সাথে পেয়ার করা যাবে না!",
noBest: "❌ | আজকের বেস্ট ম্যাচ এখনো হয়নি।",
bestTitle: "🏆 আজকের বেস্ট ম্যাচ",
error: "❌ | কিছু সমস্যা হয়েছে। আবার চেষ্টা করো।"
}
},
onStart: async function ({ api, event, args, message, usersData, getLang }) {
const { threadID, messageID, senderID, messageReply, mentions } = event;
const botID = api.getCurrentUserID();
const firstArg = (args[0] || "").toLowerCase();
const wantGif = firstArg === "gif";
try {
try {
await api.setMessageReaction("😍", messageID, () => {}, true);
} catch (e) {}
// ===== .pair best =====
if (firstArg === "best") {
const best = await fs.readJson(BEST_FILE).catch(() => null);
const today = new Date().toLocaleDateString("en-CA", { timeZone: "Asia/Dhaka" });
if (!best || best.date !== today) {
return message.reply(getLang("noBest"));
}
return message.reply(
getLang("bestTitle") +
"\n\n💞 " + best.senderName + " + " + best.targetName +
"\n⭐ Score: " + best.percent + "%\n" + best.badge
);
}
let waiting = null;
try {
waiting = await message.reply(getLang("waiting"));
} catch (e) {}
let targetID = null;
let targetName = "Partner";
let senderGender = "male";
let senderName = "You";
// রিপ্লাই / ট্যাগ
if (messageReply && messageReply.senderID) {
targetID = messageReply.senderID;
} else if (mentions && Object.keys(mentions).length) {
targetID = Object.keys(mentions)[0];
}
if (targetID && String(targetID) === String(senderID)) {
if (waiting) try { await api.unsendMessage(waiting.messageID); } catch (e) {}
return message.reply(getLang("selfPair"));
}
// Random opposite gender (SAAN style — ১টা getThreadInfo)
if (!targetID) {
const picked = await pickOppositePartner(api, threadID, senderID, botID);
if (!picked) {
if (waiting) try { await api.unsendMessage(waiting.messageID); } catch (e) {}
return message.reply(getLang("noMembers"));
}
targetID = picked.targetID;
targetName = picked.targetName;
senderGender = picked.senderGender;
const me = (picked.users || []).find(u => String(u.id) === String(senderID));
if (me?.name) senderName = me.name;
} else {
// ট্যাগ/রিপ্লাই মোডে gender + নাম
try {
const thread = await api.getThreadInfo(threadID);
const users = thread.userInfo || [];
const me = users.find(u => String(u.id) === String(senderID));
const partner = users.find(u => String(u.id) === String(targetID));
if (me?.name) senderName = me.name;
if (partner?.name) targetName = partner.name;
const g = (me?.gender || "").toUpperCase();
if (g === "FEMALE") senderGender = "female";
else if (g === "MALE") senderGender = "male";
} catch (e) {}
}
// নাম আরও নিশ্চিত করতে
try {
const n1 = await usersData.getName(senderID);
if (n1) senderName = n1;
const n2 = await usersData.getName(targetID);
if (n2) targetName = n2;
} catch (e) {}
const percent = Math.floor(Math.random() * 36) + 65; // 65–100
const badge = getBadge(percent);
const title = TITLES[Math.floor(Math.random() * TITLES.length)];
const caption = makeCaption(percent, title);
// Daily best আপডেট
const today = new Date().toLocaleDateString("en-CA", { timeZone: "Asia/Dhaka" });
const prev = await fs.readJson(BEST_FILE).catch(() => null);
if (!prev || prev.date !== today || percent > prev.percent) {
await fs.ensureDir(path.dirname(BEST_FILE));
await fs.writeJson(BEST_FILE, {
date: today,
senderName,
targetName,
percent,
badge
});
}
const body =
caption +
"\n\n👤 " + senderName +
"\n💑 " + targetName +
"\n" + badge;
const senderIdx = body.indexOf(senderName);
const targetIdx = body.indexOf(targetName, senderIdx + senderName.length);
const msgMentions = [];
if (senderIdx !== -1) {
msgMentions.push({ tag: senderName, id: senderID, fromIndex: senderIdx });
}
if (targetIdx !== -1) {
msgMentions.push({ tag: targetName, id: targetID, fromIndex: targetIdx });
}
if (msgMentions.length < 2) {
msgMentions.length = 0;
msgMentions.push({ tag: senderName, id: senderID });
msgMentions.push({ tag: targetName, id: targetID });
}
if (waiting) {
try { await api.unsendMessage(waiting.messageID); } catch (e) {}
}
await fs.ensureDir(CACHE_DIR);
let buffer = null;
let ext = "png";
if (wantGif) {
const gifUrl = RANDOM_GIFS[Math.floor(Math.random() * RANDOM_GIFS.length)];
buffer = await downloadBuffer(gifUrl);
ext = "gif";
} else {
buffer = await createTemplatePair(senderID, targetID, senderName, targetName, senderGender, percent);
if (!buffer) {
const gifUrl = RANDOM_GIFS[Math.floor(Math.random() * RANDOM_GIFS.length)];
buffer = await downloadBuffer(gifUrl);
ext = "gif";
}
}
const msgData = {
body,
mentions: msgMentions
};
if (buffer) {
const file = path.join(CACHE_DIR, "pair_" + Date.now() + "." + ext);
await fs.writeFile(file, buffer);
msgData.attachment = fs.createReadStream(file);
try {
await message.reply(msgData);
try { await fs.unlink(file); } catch (e) {}
return;
} catch (e) {
console.error("Upload failed:", e.message);
}
}
return message.reply(msgData);
} catch (err) {
console.error("Pair Error:", err);
return message.reply(getLang("error"));
}
}
};