lordceaser-baileys 2.0.28 → 2.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +392 -167
  2. package/package.json +19 -5
package/index.js CHANGED
@@ -1,192 +1,417 @@
1
- // CEASER - Premium WhatsApp Engine - lordceaser-baileys v2.0.26 - FIXED PERMANENTLY
2
- // Shows banner like PLOGME when installed
3
-
4
- const isMain = require.main === module || !module.parent || process.argv[1] && process.argv[1].includes('lordceaser-baileys');
5
-
6
- function showBanner() {
7
- const banner = `
8
- \x1b[35m
9
- ██████╗███████╗ █████╗ ███████╗███████╗██████╗
10
- ██╔════╝██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗
11
- ██║ █████╗ ███████║███████╗█████╗ ██████╔╝
12
- ██║ ██╔══╝ ██╔══██║╚════██║██╔══╝ ██╔══██╗
13
- ╚██████╗███████╗██║ ██║███████║███████╗██║ ██║
14
- ╚═════╝╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
15
- \x1b[0m
16
- \x1b[36m ⚡ CEASER - premium WhatsApp engine - lordceaser-baileys v2.0.26 FIXED ⚡\x1b[0m
17
- \x1b[32m ✅ All button types supported permanently (nativeFlow, interactiveButtons, buttons, template)\x1b[0m
18
- \x1b[32m ✅ Ping media + channel button + group responding fixed\x1b[0m
19
- \x1b[32m ✅ gstatus pic/video + thumbnail fixed\x1b[0m
20
- \x1b[32m Dashboard: http://localhost:3000\x1b[0m
21
- \x1b[34m Baileys v2.0.26 FIXED - server negotiated: 2.3000.1040735178 (latest: true)\x1b[0m
22
- `;
23
- console.log(banner);
1
+ /**
2
+ * C⁴ SOCIETY MD — WhatsApp Bot (Baileys - Pairing Code)
3
+ * Developer: ¿[ℓσя∂ ƒαмσυѕ тнє ƒαтнєя σƒ ∂υαℓ gσ∂ѕ]?[⁰⁰¹] σƒ C⁴
4
+ * Creator: +2348058314787
5
+ */
6
+
7
+ const { default: makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion } = require("@whiskeysockets/baileys");
8
+ const { Boom } = require("@hapi/boom");
9
+ const axios = require("axios");
10
+ const path = require("path");
11
+ const fs = require("fs");
12
+ const pino = require("pino");
13
+ require("dotenv").config();
14
+
15
+ const readline = require("readline");
16
+
17
+ const BOT_NAME = "C⁴ SOCIETY MD";
18
+ const DEVELOPER = "¿[ℓσя∂ ƒαмσυѕ тнє ƒαтнєя σƒ ∂υαℓ gσ∂ѕ]?[⁰⁰¹] σƒ C⁴";
19
+ const CREATOR = "+2348058314787";
20
+
21
+ function getOwnerNumber() {
22
+ return (process.env.OWNER_NUMBER || "").replace(/\D/g, "").replace(/^0+/, "");
24
23
  }
25
24
 
26
- try { showBanner(); } catch {}
25
+ const MENU_IMAGE = path.join(__dirname, "assets", "menu.jpg");
26
+
27
+ // ---------- Access control ----------
28
+ let privateMode = "public";
29
+ const whitelist = new Set();
30
+
31
+ function normalize(jid) { return jid.replace(/[^0-9]/g, ""); }
27
32
 
28
- // Export all from lib (your actual baileys code)
29
- let lib;
30
- try {
31
- lib = require('./lib');
32
- } catch (e) {
33
+ function canUseBot(senderJid, ownerJid) {
34
+ if (senderJid === ownerJid) return true;
35
+ if (privateMode === "public") return true;
36
+ if (privateMode === "self") return false;
37
+ if (privateMode === "whitelist") return whitelist.has(normalize(senderJid));
38
+ return false;
39
+ }
40
+
41
+ // ---------- Content ----------
42
+ const JOKES = [
43
+ "Why do programmers prefer dark mode? Because light attracts bugs.",
44
+ "I told my computer I needed a break — it said no problem, it'll go to sleep too.",
45
+ "There are 10 types of people: those who understand binary, and those who don't.",
46
+ ];
47
+ const QUOTES = [
48
+ '"The only way to do great work is to love what you do." — Steve Jobs',
49
+ '"Success is not final, failure is not fatal." — Winston Churchill',
50
+ '"Stay hungry, stay foolish." — Steve Jobs',
51
+ ];
52
+ const FAQ = {
53
+ hours: "We're available 9 AM – 6 PM, Monday to Saturday.",
54
+ pricing: "Please tell us what product/service you're asking about.",
55
+ contact: "Reply here and our support team will get back to you ASAP.",
56
+ location: "We're online-only — no physical location.",
57
+ };
58
+
59
+ function pickRandom(arr) { return arr[Math.floor(Math.random() * arr.length)]; }
60
+
61
+ function helpText() {
62
+ return (
63
+ `*${BOT_NAME}*\n` +
64
+ `Developer: ${DEVELOPER}\n` +
65
+ `Creator: ${CREATOR}\n\n` +
66
+ "*Commands (everyone):*\n" +
67
+ "!help — show this menu\n" +
68
+ "!joke — random joke\n" +
69
+ "!quote — random quote\n" +
70
+ "!roll — roll a dice (1–6)\n" +
71
+ "!flip — flip a coin\n" +
72
+ "!faq hours / pricing / contact / location\n" +
73
+ "!ai <question> — ask the AI assistant\n" +
74
+ "Send image with caption *!sticker* to convert it\n\n" +
75
+ "*Download commands:*\n" +
76
+ "!ytmp3 <url> — download YouTube audio (mp3)\n" +
77
+ "!ytmp4 <url> — download YouTube video (mp4)\n" +
78
+ "!tiktok <url> — download TikTok video (no watermark)\n" +
79
+ "!ig <url> — download Instagram video/photo\n" +
80
+ "!fb <url> — download Facebook video\n\n" +
81
+ "*Group commands (admin only):*\n" +
82
+ "!tag <message> — mention every member\n" +
83
+ "!kick — reply to a member's msg to kick them\n" +
84
+ "!welcome on / off — toggle welcome message\n\n" +
85
+ "*Owner only:*\n" +
86
+ "!self — lock bot to owner only\n" +
87
+ "!self off — unlock back to public\n" +
88
+ "!whitelist add 234... — whitelist a number\n" +
89
+ "!whitelist remove 234... — remove a number\n" +
90
+ "!whitelist list — show whitelisted numbers\n" +
91
+ "!whitelist on / off — toggle whitelist mode\n\n" +
92
+ `*Current mode:* ${privateMode}`
93
+ );
94
+ }
95
+
96
+ async function askAI(prompt) {
33
97
  try {
34
- lib = require('@whiskeysockets/baileys');
35
- console.log('\x1b[33m⚠️ lib/ not found, falling back to @whiskeysockets/baileys core\x1b[0m');
36
- } catch (e2) {
37
- console.log('\x1b[31m❌ Baileys core not found - run npm install\x1b[0m');
38
- lib = {};
98
+ const res = await axios.post(
99
+ "https://api.openai.com/v1/chat/completions",
100
+ { model: "gpt-4o-mini", messages: [{ role: "user", content: prompt }] },
101
+ { headers: { Authorization: `Bearer ${process.env.AI_API_KEY}`, "Content-Type": "application/json" } }
102
+ );
103
+ return res.data.choices[0].message.content;
104
+ } catch (err) {
105
+ return "Sorry, couldn't reach the AI service right now.";
39
106
  }
40
107
  }
41
108
 
42
- // ─── PERMANENT FIX FOR ALL BUTTON TYPES + PING MEDIA + GROUP RESPONDING ───
43
- const originalMakeWASocket = lib.default || lib.makeWASocket;
109
+ // ---------- Downloader functions ----------
44
110
 
45
- function normalizeButtons(content) {
46
- if (!content) return content;
47
-
48
- // If content already has interactiveButtons with correct format, keep it
49
- if (content.interactiveButtons && Array.isArray(content.interactiveButtons)) {
50
- // Ensure each has name and buttonParamsJson
51
- return content;
111
+ async function downloadYT(url, type) {
112
+ try {
113
+ const api = `https://api.ryzendesu.vip/api/downloader/${type === "mp3" ? "ytmp3" : "ytmp4"}?url=${encodeURIComponent(url)}`;
114
+ const res = await axios.get(api, { timeout: 30000 });
115
+ return res.data?.url || res.data?.link || res.data?.download || null;
116
+ } catch (err) {
117
+ return null;
52
118
  }
53
-
54
- // Convert nativeFlow: [{text, url/id}, ...] -> interactiveButtons
55
- if (content.nativeFlow && Array.isArray(content.nativeFlow)) {
56
- const flowButtons = content.nativeFlow.map(b => {
57
- if (b.url) {
58
- return { name: "cta_url", buttonParamsJson: JSON.stringify({ display_text: b.text || b.displayText || "Channel", url: b.url }) };
59
- } else if (b.id) {
60
- return { name: "quick_reply", buttonParamsJson: JSON.stringify({ display_text: b.text || b.displayText || "Button", id: b.id }) };
61
- } else if (b.text) {
62
- // If only text, assume quick_reply with text as id
63
- return { name: "quick_reply", buttonParamsJson: JSON.stringify({ display_text: b.text, id: b.text.toLowerCase().replace(/\s+/g, '_') }) };
64
- }
65
- return null;
66
- }).filter(Boolean);
67
-
68
- const newContent = { ...content };
69
- delete newContent.nativeFlow;
70
- newContent.interactiveButtons = flowButtons;
71
- return newContent;
119
+ }
120
+
121
+ async function downloadTikTok(url) {
122
+ try {
123
+ const res = await axios.get(`https://api.ryzendesu.vip/api/downloader/ttdl?url=${encodeURIComponent(url)}`, { timeout: 30000 });
124
+ return res.data?.video || res.data?.url || null;
125
+ } catch (err) {
126
+ return null;
72
127
  }
73
-
74
- // Convert buttons: [{buttonId, buttonText, type}] -> interactiveButtons
75
- if (content.buttons && Array.isArray(content.buttons)) {
76
- const flowButtons = content.buttons.map(b => {
77
- const text = b.buttonText?.displayText || b.displayText || b.text || "Button";
78
- const id = b.buttonId || b.id || text.toLowerCase().replace(/\s+/g, '_');
79
- // Check if it's URL button (cta_url)
80
- if (b.type === 2 || b.url) {
81
- return { name: "cta_url", buttonParamsJson: JSON.stringify({ display_text: text, url: b.url || b.buttonParamsJson || "https://whatsapp.com/channel/0029VbDdSaV5PO0ukeNIwY1T" }) };
82
- }
83
- return { name: "quick_reply", buttonParamsJson: JSON.stringify({ display_text: text, id: id }) };
84
- });
85
-
86
- const newContent = { ...content };
87
- delete newContent.buttons;
88
- delete newContent.headerType;
89
- newContent.interactiveButtons = flowButtons;
90
- return newContent;
128
+ }
129
+
130
+ async function downloadIG(url) {
131
+ try {
132
+ const res = await axios.get(`https://api.ryzendesu.vip/api/downloader/igdl?url=${encodeURIComponent(url)}`, { timeout: 30000 });
133
+ const items = res.data?.data || res.data?.result || [];
134
+ return items[0]?.url || null;
135
+ } catch (err) {
136
+ return null;
91
137
  }
92
-
93
- // Convert nativeFlowMessage: {buttons: [...]} -> interactiveButtons
94
- if (content.nativeFlowMessage && content.nativeFlowMessage.buttons) {
95
- const newContent = { ...content };
96
- newContent.interactiveButtons = content.nativeFlowMessage.buttons;
97
- delete newContent.nativeFlowMessage;
98
- return newContent;
138
+ }
139
+
140
+ async function downloadFB(url) {
141
+ try {
142
+ const res = await axios.get(`https://api.ryzendesu.vip/api/downloader/fbdl?url=${encodeURIComponent(url)}`, { timeout: 30000 });
143
+ return res.data?.hd || res.data?.sd || res.data?.url || null;
144
+ } catch (err) {
145
+ return null;
99
146
  }
100
-
101
- return content;
102
147
  }
103
148
 
104
- function patchSocket(sock) {
105
- if (!sock || sock._ceaserPatched) return sock;
106
-
107
- const originalSendMessage = sock.sendMessage.bind(sock);
108
-
109
- sock.sendMessage = async (jid, content, options) => {
110
- try {
111
- // Normalize all button types to interactiveButtons (supported by your Bailey)
112
- let normalized = normalizeButtons(content);
113
-
114
- // Fix ping media + buttons: if image/video + buttons, ensure proper format
115
- if (normalized && (normalized.image || normalized.video) && normalized.interactiveButtons) {
116
- // Keep image/video and interactiveButtons together - this is supported in patched version
117
- // Ensure footer exists
118
- if (!normalized.footer) normalized.footer = "C4 Society • Ping Executed";
149
+ async function sendDownload(sock, from, msg, downloadUrl, type, caption) {
150
+ try {
151
+ const response = await axios.get(downloadUrl, { responseType: "arraybuffer", timeout: 60000 });
152
+ const buffer = Buffer.from(response.data);
153
+ if (type === "audio") {
154
+ await sock.sendMessage(from, { audio: buffer, mimetype: "audio/mp4", fileName: "audio.mp3" }, { quoted: msg });
155
+ } else {
156
+ await sock.sendMessage(from, { video: buffer, caption }, { quoted: msg });
157
+ }
158
+ } catch (err) {
159
+ await sock.sendMessage(from, { text: "❌ Failed to send file. The file may be too large or the link expired." }, { quoted: msg });
160
+ }
161
+ }
162
+
163
+ const welcomeSettings = new Map();
164
+
165
+ // ---------- Main ----------
166
+ async function startBot() {
167
+ const { state, saveCreds } = await useMultiFileAuthState("auth_info");
168
+ const { version } = await fetchLatestBaileysVersion();
169
+
170
+ // Always ask for the number to pair
171
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
172
+ const phoneNumber = await new Promise((resolve) => {
173
+ rl.question("\n📱 Enter the WhatsApp number to link (with country code, no + sign):\n> ", (ans) => {
174
+ rl.close();
175
+ resolve(ans.replace(/\D/g, "").replace(/^0+/, ""));
176
+ });
177
+ });
178
+
179
+ const OWNER_JID = (process.env.OWNER_NUMBER || phoneNumber).replace(/\D/g, "") + "@s.whatsapp.net";
180
+ console.log(`\n✅ Linking number: ${phoneNumber}`);
181
+
182
+ const sock = makeWASocket({
183
+ version,
184
+ auth: state,
185
+ logger: pino({ level: "silent" }),
186
+ printQRInTerminal: false,
187
+ browser: ["C⁴ SOCIETY MD", "Chrome", "1.0.0"],
188
+ syncFullHistory: false,
189
+ markOnlineOnConnect: false,
190
+ });
191
+
192
+ // ---- PAIRING CODE ----
193
+ if (!sock.authState.creds.registered) {
194
+ console.log(`\n⏳ Requesting pairing code for: ${phoneNumber} ...\n`);
195
+ setTimeout(async () => {
196
+ try {
197
+ const code = await sock.requestPairingCode(phoneNumber);
198
+ const formatted = code.match(/.{1,4}/g)?.join("-") || code;
199
+ console.log("\n╔══════════════════════════════════════╗");
200
+ console.log("║ C⁴ SOCIETY MD — PAIRING ║");
201
+ console.log("╠══════════════════════════════════════╣");
202
+ console.log(`║ Code: ${formatted.padEnd(30)}║`);
203
+ console.log("╠══════════════════════════════════════╣");
204
+ console.log("║ Steps: ║");
205
+ console.log("║ 1. Open WhatsApp on your phone ║");
206
+ console.log("║ 2. Go to Linked Devices ║");
207
+ console.log("║ 3. Tap Link a Device ║");
208
+ console.log("║ 4. Tap Link with phone number ║");
209
+ console.log("║ 5. Enter the code above QUICKLY ║");
210
+ console.log("║ (code expires in 60 seconds) ║");
211
+ console.log("╚══════════════════════════════════════╝\n");
212
+ } catch (err) {
213
+ console.error("❌ Pairing code error:", err.message);
214
+ console.log("➡ Delete the auth_info folder and restart");
215
+ console.log("➡ Make sure the number has country code, no + sign");
216
+ console.log("➡ Example: 2348058314787");
119
217
  }
120
-
121
- // Fix group status thumbnail: if groupStatus true, ensure externalAdReply preserved
122
- if (normalized && normalized.groupStatus) {
123
- // Keep groupStatus flag for lordceaser-baileys custom
218
+ }, 5000);
219
+ }
220
+
221
+ sock.ev.on("creds.update", saveCreds);
222
+
223
+ sock.ev.on("connection.update", ({ connection, lastDisconnect }) => {
224
+ if (connection === "close") {
225
+ const shouldReconnect = new Boom(lastDisconnect?.error)?.output?.statusCode !== DisconnectReason.loggedOut;
226
+ console.log("Connection closed. Reconnecting:", shouldReconnect);
227
+ if (shouldReconnect) startBot();
228
+ } else if (connection === "open") {
229
+ console.log(`✅ ${BOT_NAME} connected successfully!`);
230
+ }
231
+ });
232
+
233
+ sock.ev.on("group-participants.update", async ({ id, participants, action }) => {
234
+ if (action !== "add") return;
235
+ if (!(welcomeSettings.get(id) ?? true)) return;
236
+ const groupMeta = await sock.groupMetadata(id);
237
+ for (const participant of participants) {
238
+ await sock.sendMessage(id, {
239
+ text: `👋 Welcome @${participant.split("@")[0]} to *${groupMeta.subject}*!`,
240
+ mentions: [participant],
241
+ });
242
+ }
243
+ });
244
+
245
+ sock.ev.on("messages.upsert", async ({ messages, type }) => {
246
+ if (type !== "notify") return;
247
+ const msg = messages[0];
248
+ if (!msg.message || msg.key.fromMe) return;
249
+
250
+ const from = msg.key.remoteJid;
251
+ const sender = msg.key.participant || msg.key.remoteJid;
252
+ const isGroup = from.endsWith("@g.us");
253
+ const isOwner = sender === OWNER_NUMBER;
254
+ const body = msg.message?.conversation || msg.message?.extendedTextMessage?.text || "";
255
+ const text = body.trim();
256
+ const lower = text.toLowerCase();
257
+ const imageMsg = msg.message?.imageMessage;
258
+
259
+ const reply = (text) => sock.sendMessage(from, { text }, { quoted: msg });
260
+
261
+ // Access control for private chats
262
+ if (!isGroup && !canUseBot(sender)) {
263
+ return reply(
264
+ privateMode === "self"
265
+ ? "🔒 Bot is in *self mode* — only the owner can use it."
266
+ : "🔒 Your number is not whitelisted to use this bot."
267
+ );
268
+ }
269
+
270
+ // Sticker from image
271
+ if (imageMsg && imageMsg.caption?.trim().toLowerCase() === "!sticker") {
272
+ const buffer = await sock.downloadMediaMessage(msg);
273
+ await sock.sendMessage(from, { sticker: buffer }, { quoted: msg });
274
+ return;
275
+ }
276
+
277
+ // Help with image
278
+ if (lower === "!help") {
279
+ const imageBuffer = fs.readFileSync(MENU_IMAGE);
280
+ await sock.sendMessage(from, { image: imageBuffer, caption: helpText() });
281
+ return;
282
+ }
283
+
284
+ // Fun commands
285
+ if (lower === "!joke") return reply(pickRandom(JOKES));
286
+ if (lower === "!quote") return reply(pickRandom(QUOTES));
287
+ if (lower === "!roll") return reply(`🎲 You rolled a ${1 + Math.floor(Math.random() * 6)}`);
288
+ if (lower === "!flip") return reply(`🪙 ${Math.random() < 0.5 ? "Heads" : "Tails"}`);
289
+
290
+ if (lower.startsWith("!faq")) {
291
+ const topic = lower.replace("!faq", "").trim();
292
+ return reply(FAQ[topic] || `Available topics: ${Object.keys(FAQ).join(", ")}\nUse: !faq <topic>`);
293
+ }
294
+
295
+ if (lower.startsWith("!ai ")) {
296
+ return reply(await askAI(text.slice(4).trim()));
297
+ }
298
+
299
+ // ---------- Download commands ----------
300
+ if (lower.startsWith("!ytmp3 ")) {
301
+ const url = text.slice(7).trim();
302
+ if (!url) return reply("Usage: !ytmp3 <YouTube URL>");
303
+ await reply("⏳ Downloading audio, please wait...");
304
+ const dlUrl = await downloadYT(url, "mp3");
305
+ if (!dlUrl) return reply("❌ Couldn't download. Check the URL and try again.");
306
+ return sendDownload(sock, from, msg, dlUrl, "audio", "🎵 Here's your audio!");
307
+ }
308
+ if (lower.startsWith("!ytmp4 ")) {
309
+ const url = text.slice(7).trim();
310
+ if (!url) return reply("Usage: !ytmp4 <YouTube URL>");
311
+ await reply("⏳ Downloading video, please wait...");
312
+ const dlUrl = await downloadYT(url, "mp4");
313
+ if (!dlUrl) return reply("❌ Couldn't download. Check the URL and try again.");
314
+ return sendDownload(sock, from, msg, dlUrl, "video", "🎬 Here's your video!");
315
+ }
316
+ if (lower.startsWith("!tiktok ")) {
317
+ const url = text.slice(8).trim();
318
+ if (!url) return reply("Usage: !tiktok <TikTok URL>");
319
+ await reply("⏳ Downloading TikTok video...");
320
+ const dlUrl = await downloadTikTok(url);
321
+ if (!dlUrl) return reply("❌ Couldn't download. Check the URL and try again.");
322
+ return sendDownload(sock, from, msg, dlUrl, "video", "🎵 Here's your TikTok!");
323
+ }
324
+ if (lower.startsWith("!ig ")) {
325
+ const url = text.slice(4).trim();
326
+ if (!url) return reply("Usage: !ig <Instagram URL>");
327
+ await reply("⏳ Downloading Instagram media...");
328
+ const dlUrl = await downloadIG(url);
329
+ if (!dlUrl) return reply("❌ Couldn't download. Make sure the post is public.");
330
+ return sendDownload(sock, from, msg, dlUrl, "video", "📸 Here's your Instagram media!");
331
+ }
332
+ if (lower.startsWith("!fb ")) {
333
+ const url = text.slice(4).trim();
334
+ if (!url) return reply("Usage: !fb <Facebook URL>");
335
+ await reply("⏳ Downloading Facebook video...");
336
+ const dlUrl = await downloadFB(url);
337
+ if (!dlUrl) return reply("❌ Couldn't download. Make sure the video is public.");
338
+ return sendDownload(sock, from, msg, dlUrl, "video", "📘 Here's your Facebook video!");
339
+ }
340
+
341
+ // Owner: !self
342
+ if (lower === "!self") {
343
+ if (!isOwner) return reply("⛔ Only the owner can use this command.");
344
+ privateMode = "self";
345
+ return reply("🔒 *Self mode ON* — only you can use the bot in private chats.");
346
+ }
347
+ if (lower === "!self off") {
348
+ if (!isOwner) return reply("⛔ Only the owner can use this command.");
349
+ privateMode = "public";
350
+ return reply("🔓 *Self mode OFF* — bot is public again.");
351
+ }
352
+
353
+ // Owner: !whitelist
354
+ if (lower.startsWith("!whitelist")) {
355
+ if (!isOwner) return reply("⛔ Only the owner can manage the whitelist.");
356
+ const args = text.slice(10).trim().split(/\s+/);
357
+ const action = args[0];
358
+ const numArg = args[1] ? normalize(args[1]) : null;
359
+
360
+ if (action === "on") { privateMode = "whitelist"; return reply("✅ *Whitelist mode ON.*"); }
361
+ if (action === "off") { privateMode = "public"; return reply("🔓 *Whitelist mode OFF.*"); }
362
+ if (action === "add" && numArg) {
363
+ whitelist.add(numArg);
364
+ privateMode = "whitelist";
365
+ return reply(`✅ *${numArg}* added to whitelist.\nWhitelist mode is now ON.`);
124
366
  }
125
-
126
- // Fix gstatus: ensure contextInfo.externalAdReply preserved
127
- if (normalized && normalized.contextInfo && normalized.contextInfo.externalAdReply) {
128
- // Preserve thumbnail
367
+ if (action === "remove" && numArg) {
368
+ whitelist.delete(numArg);
369
+ return reply(`✅ *${numArg}* removed from whitelist.`);
129
370
  }
130
-
131
- return await originalSendMessage(jid, normalized, options);
132
- } catch (e) {
133
- console.log("⚠️ sendMessage patch error, trying original:", e.message);
134
- // Fallback to original
135
- try {
136
- return await originalSendMessage(jid, content, options);
137
- } catch (e2) {
138
- console.log("❌ Original also failed:", e2.message);
139
- throw e2;
371
+ if (action === "list") {
372
+ return reply(whitelist.size === 0 ? "📋 Whitelist is empty." : `📋 *Whitelisted:*\n${[...whitelist].join("\n")}`);
140
373
  }
374
+ return reply("Usage:\n!whitelist add 234...\n!whitelist remove 234...\n!whitelist list\n!whitelist on\n!whitelist off");
141
375
  }
142
- };
143
-
144
- // Fix group responding: ensure groupSettingUpdate works even if not admin (will error but not block)
145
- const originalGroupSettingUpdate = sock.groupSettingUpdate ? sock.groupSettingUpdate.bind(sock) : null;
146
- if (originalGroupSettingUpdate) {
147
- sock.groupSettingUpdate = async (jid, setting) => {
148
- try {
149
- return await originalGroupSettingUpdate(jid, setting);
150
- } catch (e) {
151
- // If bot not admin, return error but don't crash
152
- if (e.message && e.message.includes("not admin")) {
153
- throw new Error("Bot must be admin to change group settings");
154
- }
155
- throw e;
376
+
377
+ // Group admin commands
378
+ if (isGroup) {
379
+ const groupMeta = await sock.groupMetadata(from);
380
+ const isAdmin = groupMeta.participants.find(p => p.id === sender)?.admin != null;
381
+
382
+ if (lower.startsWith("!tag")) {
383
+ if (!isAdmin) return reply("Only group admins can use !tag.");
384
+ const tagMsg = text.slice(4).trim() || "📢 Attention everyone!";
385
+ const mentions = groupMeta.participants.map(p => p.id);
386
+ return sock.sendMessage(from, { text: tagMsg, mentions });
156
387
  }
157
- };
158
- }
159
-
160
- sock._ceaserPatched = true;
161
- console.log("✅ Socket patched - all button types + ping media + group responding fixed");
162
- return sock;
163
- }
164
388
 
165
- function makeWASocketFixed(...args) {
166
- const sock = originalMakeWASocket(...args);
167
- return patchSocket(sock);
168
- }
389
+ if (lower === "!kick") {
390
+ if (!isAdmin) return reply("Only group admins can use !kick.");
391
+ const quoted = msg.message?.extendedTextMessage?.contextInfo?.participant;
392
+ if (!quoted) return reply("Reply to a member's message with !kick to remove them.");
393
+ try {
394
+ await sock.groupParticipantsUpdate(from, [quoted], "remove");
395
+ return reply("✅ Member removed.");
396
+ } catch {
397
+ return reply("Couldn't remove — make sure I'm an admin in this group.");
398
+ }
399
+ }
169
400
 
170
- // Patch lib
171
- if (lib.default) {
172
- lib.default = makeWASocketFixed;
173
- }
174
- if (lib.makeWASocket) {
175
- lib.makeWASocket = makeWASocketFixed;
176
- }
401
+ if (lower.startsWith("!welcome")) {
402
+ if (!isAdmin) return reply("Only group admins can change this setting.");
403
+ const setting = lower.replace("!welcome", "").trim();
404
+ if (setting === "on") { welcomeSettings.set(from, true); return reply("✅ Welcome messages ON."); }
405
+ if (setting === "off") { welcomeSettings.set(from, false); return reply("✅ Welcome messages OFF."); }
406
+ return reply("Use: !welcome on or !welcome off");
407
+ }
408
+ }
177
409
 
178
- // Export patched lib
179
- module.exports = lib;
180
- module.exports.CEASER = true;
181
- module.exports.version = '2.0.26-FIXED';
182
- module.exports.makeWASocket = makeWASocketFixed;
183
- if (lib.default) module.exports.default = makeWASocketFixed;
184
-
185
- // Keep other exports
186
- for (const key in lib) {
187
- if (!(key in module.exports)) {
188
- module.exports[key] = lib[key];
189
- }
410
+ // Default auto-reply
411
+ if (!text.startsWith("!")) {
412
+ return reply(`Thanks for your message! This is *${BOT_NAME}* 🤖\nSend *!help* to see what I can do.`);
413
+ }
414
+ });
190
415
  }
191
416
 
192
- console.log("\x1b[32m✅ lordceaser-baileys v2.0.26 FIXED - All button types + ping media + group responding permanently patched\x1b[0m");
417
+ startBot();
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "lordceaser-baileys",
3
- "version": "2.0.28",
4
- "description": "CEASER - Premium WhatsApp engine v2.0.28 - All button types + ping media + group responding fixed permanently - FULL 100 files",
3
+ "version": "2.0.32",
4
+ "description": "CEASER - Premium WhatsApp engine v2.0.32 - Perfect 2.0.26 + All button types + ping media + group responding + Pterodactyl fixed",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
7
7
  "license": "MIT",
8
8
  "author": "Lord Ceaser Himself",
9
- "keywords": ["whatsapp","baileys","ceaser","bot"],
9
+ "keywords": [
10
+ "whatsapp",
11
+ "baileys",
12
+ "ceaser",
13
+ "bot"
14
+ ],
10
15
  "dependencies": {
11
16
  "@adiwajshing/keyed-db": "^0.2.4",
12
17
  "@cacheable/node-cache": "^1.1.4",
@@ -25,5 +30,14 @@
25
30
  "qrcode-terminal": "^0.12.0",
26
31
  "lodash": "^4.17.21",
27
32
  "mysql2": "^3.9.7"
28
- }
29
- }
33
+ },
34
+ "files": [
35
+ "lib/",
36
+ "WAProto/",
37
+ "WASignalGroup/",
38
+ "WABinary/",
39
+ "WAMessage/",
40
+ "index.js",
41
+ "README.md"
42
+ ]
43
+ }