goat
command
suspend
No description
0
views
0
likes
0
installs
raw source
"use strict";
const fs = require("fs-extra");
const axios = require("axios");
const cheerio = require("cheerio");
const { loadImage, createCanvas } = require("canvas");
const TEMPLATE_URL = "https://i.ibb.co.com/5NTNZZW/1789528159120.png";
const REF_W = 737;
const COVER_SLOT_REF = { x: 0, y: 148, w: 737, h: 266 };
const AVATAR_CIRCLE_REF = { cx: 152, cy: 368, r: 120 };
const HEADER_NAME_Y_REF = 100;
const BIG_NAME_Y_REF = 549;
const BIG_NAME_X_REF = 26;
const HEADER_FONT_REF = 33;
const BIG_FONT_REF = 39;
const BG_FILL = "#808080";
const DEBUG_CALIBRATE = false;
module.exports = {
config: {
name: "suspend",
version: "3.0.0",
author: "EryXenX",
countDown: 5,
role: 0,
description: {
en: "Prank: shows the mentioned/replied user's profile as unavailable",
bn: "Prank: mention/reply kora user er profile 'content isn't available' dekhabe"
},
category: "fun",
guide: {
en: "{pn} @mention or reply to a message"
}
},
langs: {
en: { noMention: "❌ | Mention someone or reply to a message!", error: "❌ | Failed to generate. Try again." },
bn: { noMention: "❌ | কাউকে mention করুন বা reply করুন!", error: "❌ | তৈরি করতে সমস্যা হয়েছে।" }
},
onStart: async function ({ event, message, getLang, usersData, args, api }) {
try {
const targetID = Object.keys(event.mentions)[0]
|| (event.messageReply ? event.messageReply.senderID : null)
|| (args[0] && /^\d+$/.test(args[0]) ? args[0] : null)
|| event.senderID;
const targetName = (await usersData.getName(targetID).catch(() => null)) || "Unknown User";
const ts = Date.now();
const avtPath = __dirname + "/cache/suspend_avt_" + ts + ".jpg";
const coverPath = __dirname + "/cache/suspend_cover_" + ts + ".jpg";
const outputPath = __dirname + "/cache/suspend_out_" + ts + ".png";
const profilePicUrl = "https://graph.facebook.com/" + targetID + "/picture?height=720&width=720&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662";
const cookieStr = typeof api.getCookies === "function" ? api.getCookies() : null;
let coverUrl = null;
if (cookieStr) {
try {
coverUrl = await fetchViaMbasic(targetID, cookieStr);
console.log("[suspend] fetchViaMbasic:", coverUrl ? "OK" : "no result");
} catch (e) { console.log("[suspend] fetchViaMbasic failed:", e.message); }
}
if (!coverUrl && cookieStr) {
try {
coverUrl = await fetchCoverAlbum(targetID, cookieStr);
console.log("[suspend] fetchCoverAlbum:", coverUrl ? "OK" : "no result");
} catch (e) { console.log("[suspend] fetchCoverAlbum failed:", e.message); }
}
const [avatarBuffer, templateRes] = await Promise.all([
downloadImage(profilePicUrl, cookieStr),
axios.get(TEMPLATE_URL, { responseType: "arraybuffer" })
]);
fs.writeFileSync(avtPath, avatarBuffer);
const rawAvatar = await loadImage(avtPath);
const avatar = autoCropPadding(rawAvatar);
const template = await loadImage(Buffer.from(templateRes.data));
console.log("[suspend] template size:", template.width, "x", template.height, "| avatar size:", avatar.width, "x", avatar.height);
let coverImg = avatar;
if (coverUrl) {
try {
const coverBuffer = await downloadImage(coverUrl, cookieStr);
if (coverBuffer && coverBuffer.length > 500) {
fs.writeFileSync(coverPath, coverBuffer);
coverImg = await loadImage(coverPath);
}
} catch (_) {}
}
const canvas = createCanvas(template.width, template.height);
const ctx = canvas.getContext("2d");
const scale = template.width / REF_W;
const COVER_SLOT = {
x: COVER_SLOT_REF.x * scale,
y: COVER_SLOT_REF.y * scale,
w: COVER_SLOT_REF.w * scale,
h: COVER_SLOT_REF.h * scale
};
const avCx = AVATAR_CIRCLE_REF.cx * scale;
const avCy = AVATAR_CIRCLE_REF.cy * scale;
const avR = AVATAR_CIRCLE_REF.r * scale;
const HEADER_NAME_Y = HEADER_NAME_Y_REF * scale;
const BIG_NAME_Y = BIG_NAME_Y_REF * scale;
const BIG_NAME_X = BIG_NAME_X_REF * scale;
const headerFontSize = Math.round(HEADER_FONT_REF * scale);
const bigFontSize = Math.round(BIG_FONT_REF * scale);
ctx.fillStyle = BG_FILL;
ctx.fillRect(0, 0, template.width, template.height);
ctx.save();
ctx.beginPath();
ctx.rect(COVER_SLOT.x, COVER_SLOT.y, COVER_SLOT.w, COVER_SLOT.h);
ctx.clip();
drawCoverImage(ctx, coverImg, COVER_SLOT.x, COVER_SLOT.y, COVER_SLOT.w, COVER_SLOT.h);
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.arc(avCx, avCy, avR, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
drawCoverImage(ctx, avatar, avCx - avR, avCy - avR, avR * 2, avR * 2);
ctx.restore();
ctx.drawImage(template, 0, 0, template.width, template.height);
if (DEBUG_CALIBRATE) {
ctx.save();
ctx.strokeStyle = "#ff0000";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(avCx, avCy, avR, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
}
ctx.textAlign = "center";
ctx.fillStyle = "#050505";
ctx.font = `bold ${headerFontSize}px Sans`;
ctx.fillText(targetName, template.width / 2, HEADER_NAME_Y);
ctx.textAlign = "left";
ctx.font = `bold ${bigFontSize}px Sans`;
ctx.fillText(targetName, BIG_NAME_X, BIG_NAME_Y);
fs.writeFileSync(outputPath, canvas.toBuffer("image/png"));
await message.reply({ attachment: fs.createReadStream(outputPath) });
[avtPath, coverPath, outputPath].forEach(p => { try { fs.unlinkSync(p); } catch (_) {} });
} catch (err) {
console.error("Suspend Error:", err);
message.reply(getLang("error"));
}
}
};
function autoCropPadding(img, tolerance = 24) {
const off = createCanvas(img.width, img.height);
const octx = off.getContext("2d");
octx.drawImage(img, 0, 0);
const { data, width, height } = octx.getImageData(0, 0, img.width, img.height);
function colorAt(x, y) {
const i = (y * width + x) * 4;
return [data[i], data[i + 1], data[i + 2]];
}
function closeColor(a, b) {
return Math.abs(a[0] - b[0]) <= tolerance && Math.abs(a[1] - b[1]) <= tolerance && Math.abs(a[2] - b[2]) <= tolerance;
}
function rowIsBorder(y, ref) {
const step = Math.max(1, Math.floor(width / 60));
for (let x = 0; x < width; x += step) {
if (!closeColor(colorAt(x, y), ref)) return false;
}
return true;
}
function colIsBorder(x, ref) {
const step = Math.max(1, Math.floor(height / 60));
for (let y = 0; y < height; y += step) {
if (!closeColor(colorAt(x, y), ref)) return false;
}
return true;
}
const ref = colorAt(0, 0);
let top = 0, bottom = height - 1, left = 0, right = width - 1;
const maxTrim = Math.floor(Math.min(width, height) * 0.35);
let trimmed = 0;
while (top < bottom && rowIsBorder(top, ref) && trimmed < maxTrim) { top++; trimmed++; }
trimmed = 0;
while (bottom > top && rowIsBorder(bottom, ref) && trimmed < maxTrim) { bottom--; trimmed++; }
trimmed = 0;
while (left < right && colIsBorder(left, ref) && trimmed < maxTrim) { left++; trimmed++; }
trimmed = 0;
while (right > left && colIsBorder(right, ref) && trimmed < maxTrim) { right--; trimmed++; }
const cw = right - left + 1;
const ch = bottom - top + 1;
if (cw <= 0 || ch <= 0 || (cw === width && ch === height)) return img;
const cropped = createCanvas(cw, ch);
const cctx = cropped.getContext("2d");
cctx.drawImage(off, left, top, cw, ch, 0, 0, cw, ch);
return cropped;
}
function drawCoverImage(ctx, img, x, y, w, h) {
const scale = Math.max(w / img.width, h / img.height);
const dw = img.width * scale;
const dh = img.height * scale;
const dx = x + (w - dw) / 2;
const dy = y + (h - dh) / 2;
ctx.drawImage(img, dx, dy, dw, dh);
}
async function fetchViaMbasic(uid, cookieStr) {
const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36";
const headers = {
cookie: cookieStr,
"user-agent": UA,
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"accept-language": "en-US,en;q=0.9",
"upgrade-insecure-requests": "1",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
};
for (const url of [
`https://www.facebook.com/profile.php?id=${uid}`,
`https://www.facebook.com/profile.php?id=${uid}&sk=about`,
]) {
try {
const res = await axios.get(url, { headers, timeout: 20000, maxRedirects: 5 });
if (res.status === 200 && res.data?.length > 5000) {
const found = extractCoverFromHtml(res.data);
if (found?.url) return found.url;
}
} catch (_) {}
}
try {
const mHeaders = { ...headers, "user-agent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 Chrome/120.0.0.0 Mobile Safari/537.36" };
const res = await axios.get(`https://mbasic.facebook.com/profile.php?id=${uid}`, {
headers: mHeaders, timeout: 15000, maxRedirects: 10,
});
return extractCoverFromHtml(res.data || "")?.url || null;
} catch (_) { return null; }
}
async function fetchCoverAlbum(uid, cookieStr) {
const headers = {
cookie: cookieStr,
"accept": "text/html,application/xhtml+xml",
"accept-language": "en-US,en;q=0.9",
"user-agent": "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 Chrome/120.0.0.0 Mobile Safari/537.36",
};
try {
const res = await axios.get(`https://mbasic.facebook.com/media/albums/?id=${uid}`, { headers, timeout: 15000, maxRedirects: 10 });
const html = res.data || "";
if (!html) return null;
const albumMatch = html.match(/href="([^"]*cover[^"]*album[^"]*|[^"]*album[^"]*cover[^"]*)"/i);
if (!albumMatch) return null;
const albumUrl = "https://mbasic.facebook.com" + albumMatch[1].replace(/&/g, "&");
const res2 = await axios.get(albumUrl, { headers, timeout: 15000, maxRedirects: 10 });
return extractCoverFromHtml(res2.data || "")?.url || null;
} catch (_) { return null; }
}
function extractCoverFromHtml(html) {
if (!html) return null;
const r1 = extractCoverFromJsonText(html);
if (r1) return { url: r1 };
try {
const $ = cheerio.load(html);
const coverImg = $('img[data-imgperflogname="profileCoverPhoto"]').first();
if (coverImg.length) {
const src = coverImg.attr("src");
if (src && src.startsWith("http")) return { url: src.replace(/&/g, "&") };
}
const containerImg = $("#profile_cover_photo_container img").first();
if (containerImg.length) {
const src = containerImg.attr("src");
if (src && src.startsWith("http")) return { url: src.replace(/&/g, "&") };
}
} catch (_) {}
const boxMatch = html.match(/id="profile_cover_photo_container"[^>]*>[\s\S]{0,500}?<img[^>]+src="([^"]+)"/);
if (boxMatch) return { url: boxMatch[1].replace(/&/g, "&") };
const linkRe = /https:\/\/(?:scontent|lookaside)\.[^"'<>\s]+/g;
const found = [];
let m;
while ((m = linkRe.exec(html)) !== null) {
const u = m[0].replace(/&/g, "&");
if (!u.includes("s160x160") && !u.includes("s40x40") && !u.includes("cp0_dst-jpg"))
found.push(u);
}
const bySid = found.find(u => u.includes("_nc_sid=cc71e4"));
if (bySid) return { url: bySid };
const big = found.find(u => u.includes("_s720x720") || u.includes("1500x") || u.includes("t39.30808"));
if (big) return { url: big };
if (found[0]) return { url: found[0] };
return null;
}
function extractCoverFromJsonText(text) {
if (!text) return null;
const patterns = [
/"coverPhoto"\s*:\s*\{[^}]*"uri"\s*:\s*"([^"]+)"/,
/"cover_photo"\s*:\s*\{[^}]*"uri"\s*:\s*"([^"]+)"/,
/"cover"\s*:\s*\{[^}]*"source"\s*:\s*"([^"]+)"/,
/"cover"\s*:\s*\{"uri"\s*:\s*"([^"]+)"/,
/"cover_image"\s*:\s*\{[^}]*"uri"\s*:\s*"([^"]+)"/,
/"CoverPhoto"\s*:\s*\{[^}]*"uri"\s*:\s*"([^"]+)"/,
/"full_screen_image"\s*:\s*\{[^}]*"uri"\s*:\s*"([^"]+)"/,
/"coverPhoto"\s*:\s*"(https:[^"]+)"/,
];
for (const re of patterns) {
const m = re.exec(text);
if (m) {
return m[1]
.replace(/\\u0026/g, "&")
.replace(/\\u002F/g, "/")
.replace(/\\\//g, "/")
.replace(/\\/g, "")
.trim();
}
}
return null;
}
async function downloadImage(url, cookieStr) {
const headers = {
"accept": "image/webp,image/apng,image/*,*/*;q=0.8",
"referer": "https://www.facebook.com/",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
...(cookieStr ? { cookie: cookieStr } : {}),
};
const res = await axios.get(url, {
responseType: "arraybuffer",
timeout: 20000,
maxRedirects: 5,
headers,
});
return Buffer.from(res.data);
}