├── storage ├── tmp │ └── .bin ├── media │ ├── images.jpg │ └── thumbnail.jpg └── config.js ├── .gitignore ├── command ├── main │ ├── creator.js │ ├── ping.js │ ├── speed.js │ └── menu.js ├── owner │ ├── savefile.js │ ├── banchat.js │ ├── getfile.js │ ├── backup.js │ ├── getcmd.js │ └── savecmd.js ├── utility │ ├── afk.js │ └── _afk.js ├── tools │ ├── tourl.js │ └── upscale.js ├── exec.js ├── download │ ├── instagram.js │ └── tiktok.js └── convert │ └── sticker.js ├── package.json ├── system ├── index.js ├── lib │ ├── helper.js │ ├── plugins.js │ ├── database.js │ ├── sticker.js │ ├── function.js │ └── serialize.js ├── main.js └── handler.js └── README.md /storage/tmp/.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # file not brought 2 | system/session 3 | node_modules 4 | package-lock.json 5 | yarn.lock -------------------------------------------------------------------------------- /storage/media/images.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arifzyn19/Akane/HEAD/storage/media/images.jpg -------------------------------------------------------------------------------- /storage/media/thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arifzyn19/Akane/HEAD/storage/media/thumbnail.jpg -------------------------------------------------------------------------------- /command/main/creator.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["owner"], 3 | tags: "main", 4 | name: "owner", 5 | 6 | run: async (m, { conn }) => { 7 | try { 8 | await conn.sendContact(m.chat, global.owner, m); 9 | } catch (e) { 10 | console.error(e); 11 | m.reply("error"); 12 | } 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /command/owner/savefile.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["sf", "savefile"], 3 | example: "%p%cmd menu.js", 4 | name: "sf", 5 | tags: "owner", 6 | 7 | description: "Save File To Projects", 8 | 9 | owner: true, 10 | quoted: true, 11 | 12 | run: async (m, { conn }) => { 13 | let path = `${m.text}`; 14 | await func.fs.writeFileSync(path, m.quoted.body); 15 | m.reply(`tersimpan di ${path}`); 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /command/owner/banchat.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["banchat", "bnc"], 3 | name: "banchat", 4 | tags: "owner", 5 | 6 | owner: true, 7 | 8 | run: async (m) => { 9 | try { 10 | let chat = db.data.chats[m.chat]; 11 | chat.isBanned = true; 12 | 13 | m.reply("Chat has been banned."); 14 | } catch (error) { 15 | console.error(error); 16 | m.reply("An error occurred while trying to ban the chat."); 17 | } 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /command/main/ping.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["ping"], 3 | description: "Cek speedtest ping status", 4 | name: "ping", 5 | tags: "main", 6 | 7 | run: async (m) => { 8 | const moment = (await import("moment-timezone")).default 9 | const calculatePing = function (timestamp, now) { 10 | return moment.duration(now - moment(timestamp * 1000)).asSeconds(); 11 | } 12 | m.reply(`*Ping :* *_${calculatePing(m.timestamp, Date.now())} second(s)_*`) 13 | } 14 | } -------------------------------------------------------------------------------- /command/utility/afk.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["afk"], 3 | description: "Set your status to AFK", 4 | name: "afk", 5 | tags: "utility", 6 | 7 | run: async (m, { conn, text, args }) => { 8 | let name = m.pushName || conn.getName(m.sender); 9 | let user = global.db.data.users[m.sender]; 10 | 11 | user.afk = +new Date(); 12 | user.afkReason = text || "No Reason"; 13 | 14 | m.reply( 15 | `${name} sedang AFK dengan alasan: ${text ? text : "tidak ada alasan"}`, 16 | ); 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /command/tools/tourl.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["tourl"], 3 | description: "Convert media to url", 4 | name: "tourl", 5 | tags: "tools", 6 | 7 | run: async (m) => { 8 | const quoted = m.isQuoted ? m.quoted : m 9 | if (!quoted.isMedia) return m.reply("Reply media messages"); 10 | if (Number(quoted.msg?.fileLength) > 350000000) throw "Kegeden mas"; 11 | let media = await quoted.download(); 12 | let url = 13 | /image|video/i.test(quoted.msg.mimetype) && 14 | !/webp/i.test(quoted.msg.mimetype) 15 | ? await func.upload.telegra(media) 16 | : await func.upload.pomf(media); 17 | await m.reply(`> ${url}`) 18 | } 19 | } -------------------------------------------------------------------------------- /command/owner/getfile.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | export default { 4 | command: ["getfile", "gf"], 5 | example: "Contoh: %p%cmd menu.js", 6 | name: "getfile", 7 | tags: "owner", 8 | description: "Get File projects", 9 | 10 | owner: true, 11 | 12 | run: async (m, { conn }) => { 13 | let path = `${m.text}`; 14 | 15 | try { 16 | if (fs.existsSync(path)) { 17 | let text = fs.readFileSync(path, "utf8"); 18 | await m.reply(text); 19 | } else { 20 | await m.reply(`File ${path} tidak ditemukan.`); 21 | } 22 | } catch (error) { 23 | console.error(`Error reading file: ${error}`); 24 | m.reply(`Terjadi kesalahan saat membaca file: ${error.message}`); 25 | } 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /command/owner/backup.js: -------------------------------------------------------------------------------- 1 | import { promisify } from "util"; 2 | import cp, { exec as _exec } from "child_process"; 3 | 4 | export default { 5 | command: ["backup"], 6 | description: "Mencadangkan file", 7 | name: "backup", 8 | tags: "owner", 9 | 10 | run: async (m, { conn }) => { 11 | let exec = promisify(_exec).bind(cp); 12 | let { stdout } = await exec( 13 | "zip -r storage/backup.zip * -x 'node_modules/*'", 14 | ); 15 | 16 | if (stdout) 17 | conn.sendMessage( 18 | m.chat, 19 | { 20 | document: await func.fs.readFileSync("./storage/backup.zip"), 21 | fileName: "backup-script.zip", 22 | mimetype: "application/zip", 23 | caption: "Berhasil mencadangkan script [ ✅ ]", 24 | }, 25 | { quoted: m }, 26 | ); 27 | func.fs.unlinkSync("./storage/backup.zip"); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /command/main/speed.js: -------------------------------------------------------------------------------- 1 | import { exec } from "child_process" 2 | 3 | export default { 4 | command: ["speed", "speedtest"], 5 | description: "Cek speedtest status", 6 | name: "speed", 7 | tags: "main", 8 | 9 | run: async (m) => { 10 | const { promisify } = (await import("util")); 11 | const cp = (await import("child_process")).default; 12 | let execute = promisify(exec).bind(cp); 13 | 14 | m.reply("Testing Speed..."); 15 | 16 | let result; 17 | try { 18 | result = await execute(`speedtest --accept-license`); 19 | } catch (error) { 20 | return m.reply(`Error: ${error.message}`); 21 | } 22 | 23 | const { stdout, stderr } = result; 24 | 25 | if (stdout) { 26 | return m.reply(stdout); 27 | } 28 | 29 | if (stderr) { 30 | return m.reply(stderr); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Akane - Botz", 3 | "version": "1.0.0", 4 | "description": "Free WhatsApp Bot With ESM Module", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node system/index.js" 9 | }, 10 | "keywords": [ 11 | "whatsapp-bot" 12 | ], 13 | "author": "Arifzyn19", 14 | "license": "MIT", 15 | "dependencies": { 16 | "@whiskeysockets/baileys": "latest", 17 | "canvafy": "^7.0.4", 18 | "chalk": "^5.3.0", 19 | "child_process": "^1.0.2", 20 | "chokidar": "^3.5.3", 21 | "file-type": "^18.5.0", 22 | "fluent-ffmpeg": "^2.1.2", 23 | "glob": "^7.2.3", 24 | "https-proxy-agent": "^7.0.4", 25 | "lowdb": "^2.1.0", 26 | "moment-timezone": "^0.5.43", 27 | "node-webpmux": "^3.1.7", 28 | "syntax-error": "^1.4.0", 29 | "terminal-kit": "^3.0.1" 30 | }, 31 | "devDependencies": { 32 | "@adiwajshing/keyed-db": "^0.2.4", 33 | "axios": "^1.4.0", 34 | "jimp": "^0.16.13", 35 | "link-preview-js": "^3.0.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /command/utility/_afk.js: -------------------------------------------------------------------------------- 1 | export function before(m, { conn }) { 2 | let user = global.db.data.users[m.sender]; 3 | 4 | // Mengakhiri status AFK saat mengirim pesan 5 | if (user.afk > -1) { 6 | m.reply(` 7 | Anda telah berhenti AFK${user.afkReason ? " setelah " + user.afkReason : ""} 8 | Selama ${((new Date() - user.afk) / 1000 / 60).toFixed(1)} menit 9 | `); 10 | user.afk = -1; 11 | user.afkReason = ""; 12 | } 13 | 14 | // Memeriksa apakah pengguna yang ditandai sedang AFK 15 | let jids = [ 16 | ...new Set([ 17 | ...(m.mentionedJid || []), 18 | ...(m.quoted ? [m.quoted.sender] : []), 19 | ]), 20 | ]; 21 | for (let jid of jids) { 22 | let mentionedUser = global.db.data.users[jid]; 23 | if (!mentionedUser) continue; 24 | let afkTime = mentionedUser.afk; 25 | if (!afkTime || afkTime < 0) continue; 26 | let reason = mentionedUser.afkReason || ""; 27 | m.reply(` 28 | Jangan tag dia! 29 | Dia sedang AFK ${reason ? "dengan alasan " + reason : "tanpa alasan"} 30 | Selama ${((new Date() - afkTime) / 1000 / 60).toFixed(1)} menit 31 | `); 32 | } 33 | return true; 34 | } 35 | -------------------------------------------------------------------------------- /command/owner/getcmd.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | 4 | export default { 5 | command: ["getcmd", "getcommand"], 6 | example: "Contoh: %p%cmd main/menu", 7 | name: "getcmd", 8 | tags: "owner", 9 | description: "Mengambil isi dari sebuah cmd", 10 | 11 | owner: true, 12 | 13 | run: async (m, { conn }) => { 14 | let filePath = m.text.trim(); 15 | 16 | try { 17 | let fullPath = path.join(process.cwd(), "command", filePath + ".js"); 18 | 19 | if (fs.existsSync(fullPath)) { 20 | fs.readFile(fullPath, "utf8", (err, data) => { 21 | if (err) { 22 | console.error(`Error reading file: ${err}`); 23 | m.reply(`Terjadi kesalahan saat membaca file: ${err.message}`); 24 | } else { 25 | conn.sendMessage(m.chat, { text: data }, { quoted: m }); 26 | } 27 | }); 28 | } else { 29 | await m.reply(`File ${filePath} tidak ditemukan.`); 30 | } 31 | } catch (error) { 32 | console.error(`Error accessing file: ${error}`); 33 | m.reply(`Terjadi kesalahan saat mengakses file: ${error.message}`); 34 | } 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /system/index.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { fileURLToPath } from "url"; 4 | import { spawn } from "child_process"; 5 | 6 | let isRunning = false; 7 | 8 | async function start(file) { 9 | if (isRunning) return; 10 | isRunning = true; 11 | 12 | let __dirname = path.dirname(fileURLToPath(import.meta.url)); 13 | let args = [path.join(__dirname, file), ...process.argv.slice(2)]; 14 | let p = spawn(process.argv[0], args, { 15 | stdio: ["inherit", "inherit", "inherit", "ipc"], 16 | }); 17 | 18 | p.on("message", (data) => { 19 | console.log("[ RECEIVED ] ", data); 20 | switch (data) { 21 | case "reset": 22 | p.kill(); 23 | isRunning = false; 24 | start.apply(this, arguments); 25 | break; 26 | case "uptime": 27 | p.send(process.uptime()); 28 | break; 29 | } 30 | }); 31 | 32 | p.on("exit", (code) => { 33 | isRunning = false; 34 | console.error("Exited with code: ", code); 35 | if (code === 0) return; 36 | fs.watchFile(args[0], () => { 37 | fs.unwatchFile(args[0]); 38 | start(file); 39 | }); 40 | }); 41 | } 42 | 43 | start("main.js"); 44 | -------------------------------------------------------------------------------- /command/exec.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import util from "util"; 3 | import { fileURLToPath } from "url"; 4 | import { createRequire } from "module"; 5 | import cp, { exec as _exec } from "child_process"; 6 | let exec = util.promisify(_exec).bind(cp); 7 | 8 | export async function before(m) { 9 | if (m.isBaileys) return; 10 | if (!m.isOwner) return; 11 | 12 | if ([">", "=>"].some((a) => m.body.toLowerCase().startsWith(a))) { 13 | let __dirname = path.dirname(fileURLToPath(import.meta.url)); 14 | let require = createRequire(__dirname), 15 | _return = ""; 16 | 17 | try { 18 | _return = /await/i.test(m.text) 19 | ? eval("(async() => { " + m.text + " })()") 20 | : eval(m.text); 21 | } catch (e) { 22 | _return = e; 23 | } 24 | 25 | new Promise((resolve, reject) => { 26 | try { 27 | resolve(_return); 28 | } catch (err) { 29 | reject(err); 30 | } 31 | }) 32 | ?.then((res) => m.reply(func.format(res))) 33 | ?.catch((err) => m.reply(func.format(err))); 34 | } 35 | 36 | if (["$", "exec"].some((a) => m.body.toLowerCase().startsWith(a))) { 37 | let o; 38 | try { 39 | o = await exec(m.text); 40 | } catch (e) { 41 | o = e; 42 | } finally { 43 | let { stdout, stderr } = o; 44 | if (typeof stdout === "string" && stdout.trim()) m.reply(stdout); 45 | if (typeof stderr === "string" && stderr.trim()) m.reply(stderr); 46 | } 47 | } 48 | 49 | return !0; 50 | } 51 | -------------------------------------------------------------------------------- /command/download/instagram.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["instagram", "ig"], 3 | description: "Download Instagram reel/video/image", 4 | example: "Contoh: %p%cmd ", //%p = prefix, %cmd = command, %text = teks 5 | name: "instagram", 6 | tags: "download", 7 | 8 | run: async (m, { conn }) => { 9 | const url = m.args[0]; 10 | 11 | if (!func.isUrl(url)) 12 | return m.reply( 13 | `Invalid URL\n\nContoh: ${m.prefix + m.command} https://www.instagram.com/reel/C65wgBxraJ5/`, 14 | ); 15 | 16 | let response; 17 | const apiUrl = API("itzpire", "/download/instagram", { url: url }); 18 | 19 | try { 20 | response = await func.fetchJson(apiUrl); 21 | } catch (err) { 22 | console.error(`Error fetching Instagram reel:`, err); 23 | return m.reply("An error occurred while fetching the Instagram reel."); 24 | } 25 | 26 | if (!response || response.status !== "success" || !response.data) { 27 | return m.reply("Failed to fetch Instagram reel/video/image."); 28 | } 29 | 30 | const { author, data } = response; 31 | const videoUrl = data.url; 32 | 33 | if (!videoUrl) { 34 | return m.reply("Video URL not found."); 35 | } 36 | 37 | const replyText = ` 38 | *Author:* ${author || "Unknown"} 39 | *Type:* ${data.type || "Unknown"} 40 | `; 41 | 42 | try { 43 | await m.reply(videoUrl, { caption: replyText }); 44 | } catch (err) { 45 | conn.logger.error(err); 46 | m.reply("error"); 47 | } 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /command/convert/sticker.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["s", "sticker", "sticker"], 3 | name: "sticker", 4 | tags: "convert", 5 | 6 | run: async (m, { conn }) => { 7 | const quoted = m.isQuoted ? m.quoted : m; 8 | 9 | if (/image|video|webp/i.test(quoted.mime)) { 10 | m.reply("wait"); 11 | 12 | const buffer = await quoted.download(); 13 | if (quoted?.msg?.seconds > 10) return m.reply(`Max video 9 seconds`); 14 | 15 | let exif = { 16 | packName: "Create By", 17 | packPublish: global.wm, 18 | }; 19 | 20 | if (m.text) { 21 | let [packname, author] = m.text.split("|"); 22 | exif.packName = packname ? packname : ""; 23 | exif.packPublish = author ? author : ""; 24 | } 25 | 26 | m.reply(buffer, { asSticker: true, ...exif }); 27 | } else if (m.mentions[0]) { 28 | m.reply("wait"); 29 | let url = await conn.profilePictureUrl(m.mentions[0], "image"); 30 | let buffer = await fetch(url).then((res) => res.buffer()); 31 | m.reply(buffer, { asSticker: true, ...exif }); 32 | } else if ( 33 | /(https?:\/\/.*\.(?:png|jpg|jpeg|webp|mov|mp4|webm|gif))/i.test(m.text) 34 | ) { 35 | m.reply("wait"); 36 | let url = m.text.match( 37 | /(https?:\/\/.*\.(?:png|jpg|jpeg|webp|mov|mp4|webm|gif))/i, 38 | )[0]; 39 | let buffer = await fetch(url).then((res) => res.buffer()); 40 | m.reply(buffer, { asSticker: true, ...exif }); 41 | } else { 42 | m.reply(`Method Not Support`); 43 | } 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /command/owner/savecmd.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | 4 | export default { 5 | command: ["savecmd", "savecommand"], 6 | example: "Contoh: .savecmd main/menu", 7 | name: "savecmd", 8 | tags: "owner", 9 | description: "Simpan atau edit isi dari file command", 10 | owner: true, 11 | quoted: false, // tidak perlu di-quote selalu, bisa dari file juga 12 | 13 | run: async (m, { conn }) => { 14 | const filePath = m.text.trim(); 15 | const fullPath = path.join(process.cwd(), "command", filePath + ".js"); 16 | 17 | // Fungsi untuk menyimpan konten baru ke file 18 | const saveContent = async (content) => { 19 | try { 20 | fs.writeFileSync(fullPath, content, "utf8"); 21 | await m.reply(`File ${filePath}.js berhasil disimpan.`); 22 | } catch (error) { 23 | console.error(`Error saving command file: ${error}`); 24 | await m.reply( 25 | `Terjadi kesalahan saat menyimpan file command: ${error.message}`, 26 | ); 27 | } 28 | }; 29 | 30 | if (m.quoted) { 31 | const quotedContent = m.quoted.body?.trim() || ""; 32 | if (quotedContent) { 33 | await saveContent(quotedContent); 34 | return; 35 | } 36 | 37 | // Jika quoted adalah file, unduh filenya 38 | const quotedFile = await m.quoted.download(); 39 | if (quotedFile) { 40 | await saveContent(quotedFile.toString("utf8")); 41 | return; 42 | } 43 | } else if (m.mimetype) { 44 | // Jika bukan quoted tetapi ada file yang dilampirkan 45 | const attachedFile = await m.download(); 46 | if (attachedFile) { 47 | await saveContent(attachedFile.toString("utf8")); 48 | return; 49 | } 50 | } 51 | 52 | await m.reply( 53 | "Isi baru dari file command tidak ditemukan atau format file tidak didukung.", 54 | ); 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /command/download/tiktok.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["tiktok"], 3 | description: "Download TikTok video", 4 | example: "Contoh: %p%cmd ", //%p = prefix, %cmd = command, %text = teks 5 | name: "tiktok", 6 | tags: "download", 7 | 8 | run: async (m, { conn }) => { 9 | const url = m.args[0]; 10 | 11 | if (!func.isUrl(url)) 12 | return m.reply( 13 | `Invalid URL\n\nContoh: ${m.prefix + m.command} https://vm.tiktok.com/ZSY5tdEQW/`, 14 | ); 15 | 16 | const apiTypes = ["", "v2", "v3"]; 17 | let response; 18 | 19 | for (const type of apiTypes) { 20 | let apiUrl; 21 | if (type) { 22 | apiUrl = API("itzpire", "/download/tiktok", { url: url, type: type }); 23 | } else { 24 | apiUrl = API("itzpire", "/download/tiktok", { url: url }); 25 | } 26 | 27 | console.log(apiUrl); 28 | try { 29 | response = await func.fetchJson(apiUrl); 30 | if (response.status === "success") { 31 | break; // Break the loop if a successful response is received 32 | } 33 | } catch (err) { 34 | console.error(`Error with type ${type}:`, err); 35 | } 36 | } 37 | 38 | if (!response || response.status !== "success" || !response.data) { 39 | return m.reply("Failed to fetch TikTok video."); 40 | } 41 | 42 | console.log(response); 43 | 44 | const { desc, author, statistics, video, video1, video2, video_hd, music } = 45 | response.data; 46 | const videoUrl = video || video1 || video2 || video_hd; 47 | 48 | if (!videoUrl) { 49 | return m.reply("Video URL not found."); 50 | } 51 | 52 | const replyText = ` 53 | *Description:* ${desc || "No description"} 54 | *Author:* ${author?.nickname || "Unknown"} 55 | *Likes:* ${statistics?.likeCount || "0"} 56 | *Comments:* ${statistics?.commentCount || "0"} 57 | *Shares:* ${statistics?.shareCount || "0"} 58 | `; 59 | 60 | try { 61 | await m.reply(videoUrl, { caption: replyText }); 62 | } catch (err) { 63 | console.error(err); 64 | m.reply("An error occurred while sending the TikTok video."); 65 | } 66 | }, 67 | }; 68 | -------------------------------------------------------------------------------- /command/tools/upscale.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import FormData from "form-data"; 3 | 4 | export default { 5 | command: ["upscale", "hd", "remini"], 6 | name: "upscale", 7 | tags: "tools", 8 | 9 | run: async (m, { conn }) => { 10 | const quoted = m.isQuoted ? m.quoted : m; 11 | 12 | if (/image/i.test(quoted.mime)) { 13 | const media = await quoted.download(); 14 | 15 | try { 16 | const image = await enhance(media, "enhance"); 17 | m.reply(image, { caption: "Done" }); 18 | } catch (e) { 19 | conn.logger.error(e); 20 | m.reply("error"); 21 | } 22 | } else { 23 | m.reply(`Reply/Kirim image dengan caption ${m.prefix + m.command}`); 24 | } 25 | }, 26 | }; 27 | 28 | const enhance = (urlPath, method) => { 29 | return new Promise(async (resolve, reject) => { 30 | let Methods = ["enhance", "recolor", "dehaze"]; 31 | Methods.includes(method) ? (method = method) : (method = Methods[0]); 32 | let buffer, 33 | Form = new FormData(), 34 | scheme = "https" + "://" + "inferenceengine" + ".vyro" + ".ai/" + method; 35 | Form.append("model_version", 1, { 36 | "Content-Transfer-Encoding": "binary", 37 | contentType: "multipart/form-data; charset=uttf-8", 38 | }); 39 | Form.append("image", Buffer.from(urlPath), { 40 | filename: "enhance_image_body.jpg", 41 | contentType: "image/jpeg", 42 | }); 43 | Form.submit( 44 | { 45 | url: scheme, 46 | host: "inferenceengine" + ".vyro" + ".ai", 47 | path: "/" + method, 48 | protocol: "https:", 49 | headers: { 50 | "User-Agent": "okhttp/4.9.3", 51 | Connection: "Keep-Alive", 52 | "Accept-Encoding": "gzip", 53 | }, 54 | }, 55 | function (err, res) { 56 | if (err) reject(); 57 | let data = []; 58 | res 59 | .on("data", function (chunk, resp) { 60 | data.push(chunk); 61 | }) 62 | .on("end", () => { 63 | resolve(Buffer.concat(data)); 64 | }); 65 | res.on("error", (e) => { 66 | reject(); 67 | }); 68 | }, 69 | ); 70 | }); 71 | }; 72 | -------------------------------------------------------------------------------- /command/main/menu.js: -------------------------------------------------------------------------------- 1 | export default { 2 | command: ["menu", "help"], 3 | description: "Menampilkan list menu", 4 | name: "menu", 5 | tags: "main", 6 | 7 | run: async (m, { conn, args }) => { 8 | const selectedCategory = args[0]; 9 | 10 | if (!selectedCategory) { 11 | let body = 12 | "This bot is designed to help WhatsApp users with various features, starting from downloading videos or music, creating stickers, and many other functions.\n\n┌ ◦ *Creator* : Arifzyn\n│ ◦ *Instagram* : arifzxa19\n╰───────···\n\nPlease select a category to see the available commands."; 13 | 14 | const categories = new Set(); 15 | 16 | for (const [filePath, command] of Object.entries(global.plugins)) { 17 | const cmd = command.default || command; 18 | if ( 19 | !cmd || 20 | !cmd.command || 21 | !Array.isArray(cmd.command) || 22 | !cmd.command[0] 23 | ) { 24 | continue; 25 | } 26 | 27 | const category = cmd.tags || "General"; 28 | categories.add(category); 29 | } 30 | 31 | const sections = [ 32 | { 33 | title: "Categories", 34 | rows: Array.from(categories).map((category) => ({ 35 | title: category, 36 | id: `.menu ${category}`, 37 | description: `View commands in the ${category} category`, 38 | })), 39 | }, 40 | ]; 41 | 42 | return conn.sendListM(m.chat, body, wm, sections, "", m); 43 | } else { 44 | let body = `Commands in the ${selectedCategory} category:\n\n`; 45 | 46 | const commandsInCategory = []; 47 | 48 | for (const [filePath, command] of Object.entries(global.plugins)) { 49 | const cmd = command.default || command; 50 | if ( 51 | !cmd || 52 | !cmd.command || 53 | !Array.isArray(cmd.command) || 54 | !cmd.command[0] 55 | ) { 56 | continue; 57 | } 58 | 59 | const category = cmd.tags || "General"; 60 | if (category.toLowerCase() === selectedCategory.toLowerCase()) { 61 | commandsInCategory.push(cmd); 62 | } 63 | } 64 | 65 | commandsInCategory.forEach((cmd) => { 66 | body += `• ${cmd.name}: ${cmd.description || "No description"}\n`; 67 | }); 68 | 69 | if (commandsInCategory.length === 0) { 70 | body = `No commands found in the ${selectedCategory} category.`; 71 | } 72 | 73 | return conn.sendMessage(m.chat, { text: body }, { quoted: m }); 74 | } 75 | }, 76 | }; 77 | -------------------------------------------------------------------------------- /storage/config.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import chalk from "chalk"; 3 | import { fileURLToPath } from "url"; 4 | import Function from "../system/lib/function.js"; 5 | 6 | //—————「 Setings your bot 」—————// 7 | global.name = "Akane - Bot"; 8 | global.wm = "Made from love"; 9 | 10 | global.author = "Arifzyn"; 11 | global.packname = "Created Sticker By"; 12 | global.link = "https://github.com/Arifzyn19"; 13 | 14 | global.owner = ["6288213503541", "6285691464024"]; 15 | global.pairingNumber = "62895347198105"; 16 | 17 | global.prefix = /^[°•π÷×¶∆£¢€¥®™+✓_=|/~!?@#%^&.©^]/i; 18 | global.thumbnail = fs.readFileSync("./storage/media/images.jpg"); 19 | global.ucapan = Function.timeSpeech(); 20 | global.func = Function; 21 | 22 | global.msg = { 23 | owner: "Features can only be accessed owner!", 24 | group: "Features only accessible in group!", 25 | private: "Features only accessible private chat!", 26 | admin: "Features can only be accessed by group admin!", 27 | botAdmin: "Bot is not admin, can't use the features!", 28 | bot: "Features only accessible by me", 29 | premium: "Features only accessible by premium users", 30 | media: "Reply media...", 31 | query: "No Query?", 32 | error: 33 | "Seems to have encountered an unexpected error, please repeat your command for a while again", 34 | quoted: "Reply message...", 35 | wait: "Wait a minute...", 36 | urlInvalid: "Url Invalid", 37 | notFound: "Result Not Found!", 38 | }; 39 | 40 | global.APIs = { 41 | arifzyn: "https://api.arifzyn.tech", 42 | rose: "https://api.itsrose.rest", 43 | xyro: "https://api.xyro.fund", 44 | akane: "https://akane.my.id", 45 | itzpire: "https://www.itzpire.com", 46 | }; 47 | 48 | global.APIKeys = { 49 | "https://api.arifzyn.tech": process.env.APIKEY || "", 50 | "https://api.itsrose.rest": process.env.ROSE_KEY || "", 51 | "https://api.xyro.fund": "xyroKey", 52 | }; 53 | 54 | global.API = (name, path = "/", query = {}, apikeyqueryname) => { 55 | const baseUrl = name in global.APIs ? global.APIs[name] : name; 56 | const apiKey = apikeyqueryname ? global.APIKeys[baseUrl] : ""; 57 | const queryParams = new URLSearchParams({ 58 | ...query, 59 | ...(apikeyqueryname && apiKey ? { [apikeyqueryname]: apiKey } : {}), 60 | }); 61 | 62 | return baseUrl + path + (queryParams.toString() ? "?" + queryParams : ""); 63 | }; 64 | 65 | //—————「 Don"t change it 」—————// 66 | let file = fileURLToPath(import.meta.url); 67 | fs.watchFile(file, () => { 68 | fs.unwatchFile(file); 69 | console.log(chalk.redBright("Update config.js")); 70 | import(`${file}?update=${Date.now()}`); 71 | }); 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png)](#table-of-contents) 2 | 3 |

4 | 5 |

6 | 7 |

Akane - Bot

8 | 9 |

10 | 11 |

12 | 13 |

14 | 15 | 16 | ## Konfigurasi ⚙️ 17 | 18 | Mengedit nomor owner & nama bot di [`config.js`](https://github.com/Arifzyn19/Akane/blob/main/storage/config.js) 19 | 20 | ## Untuk user windows/rdp 💻 21 | 22 | Instal alat ini terlebih dahulu sebelum menjalankan skrip 23 | 24 | - Download And Install Git [`Click Here`](https://git-scm.com/downloads) 25 | - Download And Install NodeJS [`Click Here`](https://nodejs.org/en/download) 26 | - Download And Install FFmpeg [`Click Here`](https://ffmpeg.org/download.html) (**Jangan Lupa Tambahkan FFmpeg ke variabel lingkungan PATH**) 27 | - Download And Install ImageMagick [`Click Here`](https://imagemagick.org/script/download.php) 28 | 29 | ## Untuk user termux/ubuntu/ssh 30 | 31 | - apt update && apt upgrade -y 32 | - apt install nodejs imagemagick ffmpeg -y 33 | - node -v 34 | - jika versinya masih di bawah 17, gunakan langkah dibawah ini 35 | - curl -s https://deb.nodesource.com/setup_19.x | sudo bash 36 | - apt-get install -y nodejs 37 | 38 | ```bash 39 | git clone https://github.com/ArifzynXD/Akane 40 | cd Akane 41 | npm install 42 | npm update 43 | ``` 44 | 45 | ## Run ⏳ 46 | 47 | ```bash 48 | npm start / node system/index.js 49 | ``` 50 | 51 | ## Contoh membuat plugin 52 | 53 | ```js 54 | export default { 55 | //kosongkan saja jika ingin mematikan 56 | command: [""], 57 | description: "", 58 | example: "", //%p = prefix, %cmd = command, %text = teks 59 | name: "", 60 | tags: "", 61 | 62 | //ubah ke true jika ingin menyalakan 63 | admin: false, 64 | botAdmin: false, 65 | group: false, 66 | limit: false, 67 | loading: false, 68 | owner: false, 69 | premium: false, 70 | private: false, 71 | quoted: false, 72 | register: false, 73 | media: { 74 | audio: false, 75 | image: false, 76 | sticker: false, 77 | video: false, 78 | }, 79 | 80 | run: async (m, { conn, text, args, isPrem, command }) => { 81 | //your script code 82 | }, 83 | }; 84 | ``` 85 | 86 | ## 📮 S&K 87 | 88 | 1. Tidak untuk dijual 89 | 2. Jangan lupa beri bintang pada repo ini 90 | 3. Jika Anda memiliki masalah, hubungi saya [`WhatsApp`](https://wa.me/62895347198105) 91 | 92 | ## Thanks to ✨ 93 | 94 | - [`Allah SWT`] 95 | - [`My parents`] 96 | - [`All Friends`] 97 | - [`All Contributors`] 98 | - [`All Creator Bot`] 99 | - [`Whiskeysockets/Baileys`](https://github.com/WhiskeySockets/Baileys) 100 | - [`Amirul Dev`](https://github.com/amiruldev20) 101 | - [`Hisoka`](https://github.com/Hisoka-Morrou) 102 | - [`Xiao Yan?`](https://github.com/ImYanXiao) 103 | - [`AlisaOfc`](https://github.com/AlisaOfc) 104 | - 105 | -------------------------------------------------------------------------------- /system/lib/helper.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import os from "os"; 3 | import path from "path"; 4 | import { fileURLToPath, pathToFileURL } from "url"; 5 | import { createRequire } from "module"; 6 | import fs from "fs"; 7 | import Stream, { Readable } from "stream"; 8 | 9 | /** 10 | * @param {ImportMeta | string} pathURL 11 | * @param {boolean?} rmPrefix if value is `'true'`, it will remove `'file://'` prefix, if windows it will automatically false 12 | */ 13 | const __filename = function filename( 14 | pathURL = import.meta, 15 | rmPrefix = os.platform() !== "win32", 16 | ) { 17 | const path = 18 | /** @type {ImportMeta} */ (pathURL).url || /** @type {String} */ (pathURL); 19 | return rmPrefix 20 | ? /file:\/\/\//.test(path) 21 | ? fileURLToPath(path) 22 | : path 23 | : /file:\/\/\//.test(path) 24 | ? path 25 | : pathToFileURL(path).href; 26 | }; 27 | 28 | /** @param {ImportMeta | string} pathURL */ 29 | const __dirname = function dirname(pathURL) { 30 | const dir = __filename(pathURL, true); 31 | const regex = /\/$/; 32 | return regex.test(dir) 33 | ? dir 34 | : fs.existsSync(dir) && fs.statSync(dir).isDirectory() 35 | ? dir.replace(regex, "") 36 | : path.dirname(dir); // windows 37 | }; 38 | 39 | /** @param {ImportMeta | string} dir */ 40 | const __require = function require(dir = import.meta) { 41 | const path = 42 | /** @type {ImportMeta} */ (dir).url || /** @type {String} */ (dir); 43 | return createRequire(path); 44 | }; 45 | /** @param {string} file */ 46 | const checkFileExists = (file) => 47 | fs.promises 48 | .access(file, fs.constants.F_OK) 49 | .then(() => true) 50 | .catch(() => false); 51 | 52 | /** 53 | * @param {Readable} stream 54 | * @param {string} file 55 | * @returns {Promise} 56 | */ 57 | const saveStreamToFile = (stream, file) => 58 | new Promise((resolve, reject) => { 59 | const writable = stream.pipe(fs.createWriteStream(file)); 60 | writable.once("finish", () => { 61 | resolve(); 62 | writable.destroy(); 63 | }); 64 | writable.once("error", () => { 65 | reject(); 66 | writable.destroy(); 67 | }); 68 | }); 69 | 70 | const kDestroyed = Symbol("kDestroyed"); 71 | const kIsReadable = Symbol("kIsReadable"); 72 | const isReadableNodeStream = (obj, strict = false) => { 73 | return !!( 74 | ( 75 | obj && 76 | typeof obj.pipe === "function" && 77 | typeof obj.on === "function" && 78 | (!strict || 79 | (typeof obj.pause === "function" && 80 | typeof obj.resume === "function")) && 81 | (!obj._writableState || obj._readableState?.readable !== false) && // Duplex 82 | (!obj._writableState || obj._readableState) 83 | ) // Writable has .pipe. 84 | ); 85 | }; 86 | const isNodeStream = (obj) => { 87 | return ( 88 | obj && 89 | (obj._readableState || 90 | obj._writableState || 91 | (typeof obj.write === "function" && typeof obj.on === "function") || 92 | (typeof obj.pipe === "function" && typeof obj.on === "function")) 93 | ); 94 | }; 95 | const isDestroyed = (stream) => { 96 | if (!isNodeStream(stream)) return null; 97 | const wState = stream._writableState; 98 | const rState = stream._readableState; 99 | const state = wState || rState; 100 | return !!(stream.destroyed || stream[kDestroyed] || state?.destroyed); 101 | }; 102 | const isReadableFinished = (stream, strict) => { 103 | if (!isReadableNodeStream(stream)) return null; 104 | const rState = stream._readableState; 105 | if (rState?.errored) return false; 106 | if (typeof rState?.endEmitted !== "boolean") return null; 107 | return !!( 108 | rState.endEmitted || 109 | (strict === false && rState.ended === true && rState.length === 0) 110 | ); 111 | }; 112 | const isReadableStream = (stream) => { 113 | if (typeof Stream.isReadable === "function") return Stream.isReadable(stream); 114 | if (stream && stream[kIsReadable] != null) return stream[kIsReadable]; 115 | if (typeof stream?.readable !== "boolean") return null; 116 | if (isDestroyed(stream)) return false; 117 | return ( 118 | (isReadableNodeStream(stream) && 119 | !!stream.readable && 120 | !isReadableFinished(stream)) || 121 | stream instanceof fs.ReadStream || 122 | stream instanceof Readable 123 | ); 124 | }; 125 | 126 | export default { 127 | __filename, 128 | __dirname, 129 | __require, 130 | checkFileExists, 131 | 132 | saveStreamToFile, 133 | isReadableStream, 134 | }; 135 | -------------------------------------------------------------------------------- /system/lib/plugins.js: -------------------------------------------------------------------------------- 1 | import fs, { existsSync, watch } from "fs"; 2 | import { join, resolve } from "path"; 3 | import * as os from "os"; 4 | import syntaxerror from "syntax-error"; 5 | import Helper from "./helper.js"; 6 | 7 | const __dirname = Helper.__dirname(import.meta); 8 | const rootDirectory = Helper.__dirname(join(__dirname, "../")); 9 | const pluginFolder = Helper.__dirname(join(__dirname, "../../command")); 10 | const pluginFilter = (filename) => /\.js$/.test(filename); 11 | 12 | async function importFile(module) { 13 | module = Helper.__filename(module); 14 | const module_ = await import(`${module}?id=${Date.now()}`); 15 | const result = module_ && "default" in module_ ? module_.default : module_; 16 | return result; 17 | } 18 | 19 | let watcher = {}; 20 | let plugins = {}; 21 | let pluginFolders = []; 22 | 23 | /** 24 | * Load files from plugin folder as plugins 25 | */ 26 | async function loadPluginFiles( 27 | pluginFolder = pluginFolder, 28 | pluginFilter = pluginFilter, 29 | opts = { recursiveRead: false }, 30 | ) { 31 | const folder = resolve(pluginFolder); 32 | if (folder in watcher) return; 33 | pluginFolders.push(folder); 34 | 35 | const paths = await fs.promises.readdir(pluginFolder); 36 | await Promise.all( 37 | paths.map(async (path) => { 38 | const resolved = join(folder, path); 39 | const dirname = Helper.__filename(resolved, true); 40 | const formattedFilename = formatFilename(resolved); 41 | try { 42 | const stats = await fs.promises.lstat(dirname); 43 | if (!stats.isFile()) { 44 | if (opts.recursiveRead) 45 | await loadPluginFiles(dirname, pluginFilter, opts); 46 | return; 47 | } 48 | 49 | const filename = Helper.__filename(resolved); 50 | const isValidFile = pluginFilter(filename); 51 | if (!isValidFile) return; 52 | const module = await importFile(filename); 53 | if (module) plugins[formattedFilename] = module; 54 | } catch (e) { 55 | opts.logger?.error(e, `error while requiring ${formattedFilename}`); 56 | delete plugins[formattedFilename]; 57 | } 58 | }), 59 | ); 60 | 61 | const watching = watch( 62 | folder, 63 | reload.bind(null, { 64 | logger: opts.logger, 65 | pluginFolder, 66 | pluginFilter, 67 | }), 68 | ); 69 | watching.on("close", () => deletePluginFolder(folder, true)); 70 | watcher[folder] = watching; 71 | 72 | return (plugins = sortedPlugins(plugins)); 73 | } 74 | 75 | /** 76 | * Delete and stop watching the folder 77 | */ 78 | function deletePluginFolder(folder, isAlreadyClosed = false) { 79 | const resolved = resolve(folder); 80 | if (!(resolved in watcher)) return; 81 | if (!isAlreadyClosed) watcher[resolved].close(); 82 | delete watcher[resolved]; 83 | pluginFolders.splice(pluginFolders.indexOf(resolved), 1); 84 | } 85 | 86 | /** 87 | * Reload file to load latest changes 88 | */ 89 | async function reload( 90 | { logger, pluginFolder = pluginFolder, pluginFilter = pluginFilter }, 91 | _ev, 92 | filename, 93 | ) { 94 | if (pluginFilter(filename)) { 95 | const file = Helper.__filename(join(pluginFolder, filename), true); 96 | const formattedFilename = formatFilename(file); 97 | if (formattedFilename in plugins) { 98 | if (existsSync(file)) 99 | logger?.info(`updated plugin - '${formattedFilename}'`); 100 | else { 101 | logger?.warn(`deleted plugin - '${formattedFilename}'`); 102 | return delete plugins[formattedFilename]; 103 | } 104 | } else logger?.info(`new plugin - '${formattedFilename}'`); 105 | const src = await fs.promises.readFile(file); 106 | let err = syntaxerror(src, filename, { 107 | sourceType: "module", 108 | allowAwaitOutsideFunction: true, 109 | }); 110 | if (err) 111 | logger?.error(err, `syntax error while loading '${formattedFilename}'`); 112 | else 113 | try { 114 | const module = await importFile(file); 115 | if (module) plugins[formattedFilename] = module; 116 | } catch (e) { 117 | logger?.error(e, `error require plugin '${formattedFilename}'`); 118 | delete plugins[formattedFilename]; 119 | } finally { 120 | plugins = sortedPlugins(plugins); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Format filename to a relative path 127 | */ 128 | function formatFilename(filename) { 129 | let dir = join(rootDirectory, "./"); 130 | if (os.platform() === "win32") dir = dir.replace(/\\/g, "\\\\"); 131 | const regex = new RegExp(`^${dir}`); 132 | const formatted = filename.replace(regex, ""); 133 | return formatted; 134 | } 135 | 136 | /** 137 | * Sort plugins by their keys 138 | */ 139 | function sortedPlugins(plugins) { 140 | return Object.fromEntries( 141 | Object.entries(plugins).sort(([a], [b]) => a.localeCompare(b)), 142 | ); 143 | } 144 | 145 | export { 146 | pluginFolder, 147 | pluginFilter, 148 | plugins, 149 | watcher, 150 | pluginFolders, 151 | loadPluginFiles, 152 | deletePluginFolder, 153 | reload, 154 | }; 155 | -------------------------------------------------------------------------------- /system/lib/database.js: -------------------------------------------------------------------------------- 1 | import { Low, JSONFile } from "lowdb"; 2 | import path from "path"; 3 | 4 | export default class Database { 5 | constructor(filename) { 6 | this.fileName = path.join( 7 | process.cwd(), 8 | "storage", 9 | filename || "database.json", 10 | ); 11 | this.db = new Low(new JSONFile(this.fileName)); 12 | this.READ = false; 13 | this.data = null; 14 | } 15 | 16 | async loadDatabase() { 17 | if (this.READ) { 18 | return new Promise((resolve) => { 19 | const intervalId = setInterval(async () => { 20 | if (!this.READ) { 21 | clearInterval(intervalId); 22 | resolve(this.data === null ? this.loadDatabase() : this.data); 23 | } 24 | }, 1000); 25 | }); 26 | } 27 | 28 | if (this.data !== null) return; 29 | 30 | this.READ = true; 31 | await this.db.read().catch(console.error); 32 | this.READ = false; 33 | this.data = { 34 | users: {}, 35 | chats: {}, 36 | stats: {}, 37 | msgs: {}, 38 | sticker: {}, 39 | settings: {}, 40 | ...(this.db.data || {}), 41 | }; 42 | 43 | // Set default data if undefined 44 | this.db.data = this.data; 45 | } 46 | 47 | async writeDatabase() { 48 | this.db.data = this.data; 49 | await this.db.write().catch(console.error); 50 | } 51 | 52 | load(m, db) { 53 | const isNumber = (x) => typeof x === "number" && !isNaN(x); 54 | const isBoolean = (x) => typeof x === "boolean" && Boolean(x); 55 | let user = db.data.users[m.sender], 56 | chat = db.data.chats[m.chat], 57 | sett = db.data.settings; 58 | 59 | if (typeof user !== "object") db.data.users[m.sender] = {}; 60 | if (user) { 61 | if (!("lastChat" in user)) user.lastChat = new Date() * 1; 62 | if (!isBoolean(user.banned)) user.banned = false; 63 | if (!("bannedReason" in user)) user.bannedReason = ""; 64 | if (!isNumber(user.afk)) user.afk = -1; 65 | if (!("afkReason" in user)) user.afkReason = ""; 66 | if (!isBoolean(user.registered)) user.registered = false; 67 | if (!isNumber(user.warn)) user.warn = 0; 68 | 69 | if (!user.registered) { 70 | if (!isNumber(user.age)) user.age = 0; 71 | if (!("name" in user)) user.name = m.pushName; 72 | if (!isNumber(user.regTime)) user.regTime = -1; 73 | } 74 | 75 | if (!isNumber(user.limit)) user.limit = 50; 76 | if (!isNumber(user.glimit)) user.glimit = 30; 77 | if (!isNumber(user.balance)) user.balance = 0; 78 | if (!isNumber(user.exp)) user.exp = 0; 79 | if (!isNumber(user.level)) user.level = 1; 80 | if (!isNumber(user.hit)) user.hit = 1; 81 | 82 | if (!isNumber(user.lastclaim)) user.lastclaim = 0; 83 | if (!isBoolean(user.autolevelup)) user.autolevelup = false; 84 | if (!user.grade) user.grade = "Newbie"; 85 | 86 | if (!isBoolean(user.premium)) user.premium = false; 87 | if (!isNumber(user.premiumTime)) user.premiumTime = 0; 88 | } else { 89 | db.data.users[m.sender] = { 90 | lastChat: new Date() * 1, 91 | name: m.pushName, 92 | banned: false, 93 | bannedReason: "", 94 | afk: -1, 95 | afkReason: "", 96 | age: 0, 97 | registered: false, 98 | regTime: -1, 99 | warn: 0, 100 | 101 | limit: 50, 102 | glimit: 30, 103 | balance: 0, 104 | exp: 100, 105 | level: 1, 106 | hit: 0, 107 | 108 | lastclaim: 0, 109 | grade: "Newbie", 110 | autolevelup: false, 111 | 112 | premium: false, 113 | premiumTime: 0, 114 | }; 115 | } 116 | let openai = db.data.users[m.sender].openai; 117 | if (typeof openai !== "object") db.data.users[m.sender].openai = {}; 118 | if (openai) { 119 | if (!("messages" in openai)) openai.messages = []; 120 | if (!("model" in openai)) openai.model = ""; 121 | if (!isBoolean(openai.chat)) openai.chat = false; 122 | } else { 123 | db.data.users[m.sender].openai = { 124 | messages: [], 125 | chat: false, 126 | model: "", 127 | }; 128 | } 129 | let life = db.data.users[m.sender].life; 130 | if (typeof life !== "object") db.data.users[m.sender].life = {}; 131 | if (life) { 132 | if (!("name" in life)) life.name = ""; 133 | if (!("gender" in life)) life.gender = ""; 134 | if (!("age" in life)) life.age = ""; 135 | if (!isBoolean(life.verified)) life.verified = false; 136 | 137 | if (!("waifu" in life)) life.waifu = ""; 138 | if (!isNumber(life.exp)) life.exp = 0; 139 | if (!isNumber(life.lastkencan)) life.lastkencan = 0; 140 | if (!isNumber(life.money)) life.money = 0; 141 | if (!isNumber(life.gamepas)) life.gamepas = 0; 142 | 143 | if (!isNumber(life.id)) life.id = 0; 144 | if (!("about" in life)) life.about = ""; 145 | } else { 146 | db.data.users[m.sender].life = { 147 | name: "", 148 | gender: "", 149 | age: "", 150 | verified: false, 151 | 152 | waifu: "", 153 | exp: 0, 154 | lastkencan: 0, 155 | money: 0, 156 | gamepas: 0, 157 | 158 | id: "", 159 | about: "", 160 | }; 161 | } 162 | 163 | if (m.isGroup) { 164 | if (typeof chat !== "object") db.data.chats[m.chat] = {}; 165 | if (chat) { 166 | if (!isBoolean(chat.antibot)) chat.antibot = false; 167 | if (!isBoolean(chat.antidelete)) chat.antidelete = true; 168 | if (!isBoolean(chat.antilink)) chat.antilink = false; 169 | if (!isBoolean(chat.antispam)) chat.antispam = false; 170 | if (!isBoolean(chat.antitoxic)) chat.antitoxic = false; 171 | if (!isBoolean(chat.detect)) chat.detect = true; 172 | if (!isNumber(chat.expired)) chat.expired = 0; 173 | if (!isBoolean(chat.isBanned)) chat.isBanned = false; 174 | if (!isBoolean(chat.nsfw)) chat.nsfw = false; 175 | if (!isBoolean(chat.simi)) chat.simi = false; 176 | if (!isBoolean(chat.viewOnce)) chat.viewonce = false; 177 | if (!isBoolean(chat.welcome)) chat.welcome = true; 178 | } else { 179 | db.data.chats[m.chat] = { 180 | antibot: false, 181 | antidelete: true, 182 | antilink: false, 183 | antispam: false, 184 | antitoxic: false, 185 | detect: true, 186 | expired: 0, 187 | isBanned: false, 188 | nsfw: false, 189 | simi: false, 190 | viewonce: false, 191 | welcome: true, 192 | }; 193 | } 194 | } 195 | 196 | if (typeof sett !== "object") db.data.settings = {}; 197 | if (sett) { 198 | if (!isBoolean(sett.anticall)) sett.anticall = true; 199 | if (!isBoolean(sett.autoread)) sett.autoread = false; 200 | if (!isBoolean(sett.gconly)) sett.gconly = false; 201 | if (!isBoolean(sett.pconly)) sett.pconly = false; 202 | if (!isBoolean(sett.queque)) sett.queque = false; 203 | if (!isBoolean(sett.self)) sett.self = false; 204 | } else { 205 | db.data.settings = { 206 | anticall: true, 207 | autoread: false, 208 | gconly: false, 209 | pconly: false, 210 | queque: false, 211 | self: false, 212 | }; 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /system/lib/sticker.js: -------------------------------------------------------------------------------- 1 | import Func from "./function.js"; 2 | 3 | import fs from "fs"; 4 | import path from "path"; 5 | import axios from "axios"; 6 | import Crypto from "crypto"; 7 | import ff from "fluent-ffmpeg"; 8 | import webp from "node-webpmux"; 9 | import { fileTypeFromBuffer } from "file-type"; 10 | 11 | async function imageToWebp(media) { 12 | const tmpFileOut = path.join( 13 | process.cwd(), 14 | "storage/tmp", 15 | await Func.getRandom("webp"), 16 | ); 17 | const tmpFileIn = path.join( 18 | process.cwd(), 19 | "storage/tmp", 20 | await Func.getRandom("jpg"), 21 | ); 22 | 23 | fs.writeFileSync(tmpFileIn, media); 24 | 25 | await new Promise((resolve, reject) => { 26 | ff(tmpFileIn) 27 | .on("error", reject) 28 | .on("end", () => resolve(true)) 29 | .addOutputOptions([ 30 | "-vcodec", 31 | "libwebp", 32 | "-vf", 33 | "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15, pad=320:320:-1:-1:color=white@0.0, split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse", 34 | ]) 35 | .toFormat("webp") 36 | .save(tmpFileOut); 37 | }); 38 | 39 | const buff = fs.readFileSync(tmpFileOut); 40 | fs.promises.unlink(tmpFileOut); 41 | fs.promises.unlink(tmpFileIn); 42 | return buff; 43 | } 44 | 45 | async function videoToWebp(media) { 46 | const tmpFileOut = path.join( 47 | process.cwd(), 48 | "storage/tmp", 49 | await Func.getRandom("webp"), 50 | ); 51 | const tmpFileIn = path.join( 52 | process.cwd(), 53 | "storage/tmp", 54 | await Func.getRandom("mp4"), 55 | ); 56 | 57 | fs.writeFileSync(tmpFileIn, media); 58 | 59 | await new Promise((resolve, reject) => { 60 | ff(tmpFileIn) 61 | .on("error", reject) 62 | .on("end", () => resolve(true)) 63 | .addOutputOptions([ 64 | "-vcodec", 65 | "libwebp", 66 | "-vf", 67 | "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15, pad=320:320:-1:-1:color=white@0.0, split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse", 68 | "-loop", 69 | "0", 70 | "-ss", 71 | "00:00:00.0", 72 | "-t", 73 | "00:00:05.0", 74 | "-preset", 75 | "default", 76 | "-an", 77 | "-vsync", 78 | "0", 79 | ]) 80 | .toFormat("webp") 81 | .save(tmpFileOut); 82 | }); 83 | 84 | const buff = fs.readFileSync(tmpFileOut); 85 | fs.promises.unlink(tmpFileOut); 86 | fs.promises.unlink(tmpFileIn); 87 | return buff; 88 | } 89 | 90 | async function writeExif(media, metadata) { 91 | let wMedia = /webp/.test(media.mimetype) 92 | ? media.data 93 | : /image/.test(media.mimetype) 94 | ? await imageToWebp(media.data) 95 | : /video/.test(media.mimetype) 96 | ? await videoToWebp(media.data) 97 | : ""; 98 | const tmpFileOut = path.join( 99 | process.cwd(), 100 | "storage/tmp", 101 | await Func.getRandom("webp"), 102 | ); 103 | const tmpFileIn = path.join( 104 | process.cwd(), 105 | "storage/tmp", 106 | await Func.getRandom("webp", "15"), 107 | ); 108 | 109 | fs.writeFileSync(tmpFileIn, wMedia); 110 | 111 | if (Object.keys(metadata).length != 0) { 112 | const img = new webp.Image(); 113 | const opt = { 114 | packId: metadata?.packId ? metadata.packId : "https://nhentai.net", 115 | packName: metadata?.packName ? metadata.packName : "Stiker dibuat oleh :", 116 | packPublish: metadata?.packPublish ? metadata.packPublish : "Arifzyn", 117 | packEmail: metadata?.packEmail 118 | ? metadata.packEmail 119 | : "arifzyn906@gmail.com", 120 | packWebsite: metadata?.packWebsite 121 | ? metadata.packWebsite 122 | : "https://nhentai.net", 123 | androidApp: metadata?.androidApp 124 | ? metadata.androidApp 125 | : "https://play.google.com/store/apps/details?id=com.bitsmedia.android.muslimpro", 126 | iOSApp: metadata?.iOSApp 127 | ? metadata.iOSApp 128 | : "https://apps.apple.com/id/app/muslim-pro-al-quran-adzan/id388389451?|=id", 129 | emojis: metadata?.emojis ? metadata.emojis : [], 130 | isAvatar: metadata?.isAvatar ? metadata.isAvatar : 0, 131 | }; 132 | const json = { 133 | "sticker-pack-id": opt.packId, 134 | "sticker-pack-name": opt.packName, 135 | "sticker-pack-publisher": opt.packPublish, 136 | "sticker-pack-publisher-email": opt.packEmail, 137 | "sticker-pack-publisher-website": opt.packWebsite, 138 | "android-app-store-link": opt.androidApp, 139 | "ios-app-store-link": opt.iOSApp, 140 | emojis: opt.emojis, 141 | "is-avatar-sticker": opt.isAvatar, 142 | }; 143 | const exifAttr = Buffer.from([ 144 | 0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 145 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 146 | ]); 147 | const jsonBuff = Buffer.from(JSON.stringify(json), "utf-8"); 148 | const exif = Buffer.concat([exifAttr, jsonBuff]); 149 | 150 | exif.writeUIntLE(jsonBuff.length, 14, 4); 151 | await img.load(tmpFileIn); 152 | fs.promises.unlink(tmpFileIn); 153 | img.exif = exif; 154 | await img.save(tmpFileOut); 155 | 156 | return tmpFileOut; 157 | } 158 | } 159 | 160 | async function webp2mp4File(source) { 161 | return new Promise((resolve, reject) => { 162 | const form = new Func.FormData(); 163 | let isUrl = typeof source === "string" && /https?:\/\//.test(source); 164 | 165 | form.append("new-image-url", isUrl ? source : ""); 166 | form.append("new-image", isUrl ? "" : source, Date.now() + "-image.webp"); 167 | Func.axios({ 168 | method: "post", 169 | url: "https://s6.ezgif.com/webp-to-mp4", 170 | data: form, 171 | headers: { 172 | "Content-Type": `multipart/form-data; boundary=${form._boundary}`, 173 | }, 174 | }) 175 | .then(({ data }) => { 176 | const bodyFormThen = new Func.FormData(); 177 | const $ = Func.cheerio.load(data); 178 | const file = $("input[name='file']").attr("value"); 179 | const token = $("input[name='token']").attr("value"); 180 | const convert = $("input[name='file']").attr("value"); 181 | 182 | bodyFormThen.append("file", file); 183 | bodyFormThen.append("convert", "Convert WebP to MP4!"); 184 | Func.axios({ 185 | method: "post", 186 | url: "https://ezgif.com/webp-to-mp4/" + file, 187 | data: bodyFormThen, 188 | headers: { 189 | "Content-Type": `multipart/form-data; boundary=${bodyFormThen._boundary}`, 190 | }, 191 | }) 192 | .then(({ data }) => { 193 | const $ = Func.cheerio.load(data); 194 | const result = 195 | "https:" + 196 | $("div#output > p.outfile > video > source").attr("src"); 197 | 198 | resolve(result); 199 | }) 200 | .catch(reject); 201 | }) 202 | .catch(reject); 203 | }); 204 | } 205 | 206 | async function uploadFile(buffer) { 207 | const form = new Func.FormData(); 208 | const { ext } = await fileTypeFromBuffer(buffer); 209 | 210 | form.append("file", buffer, await Func.getRandom(ext)); 211 | let a = await axios.post("https://filezone.my.id/upload", form, { 212 | headers: { 213 | accept: "*/*", 214 | "accept-language": "en-US,en;q=0.9,id;q=0.8", 215 | "content-type": `multipart/form-data; boundary=${form._boundary}`, 216 | }, 217 | }); 218 | return a.data.result; 219 | } 220 | 221 | export { uploadFile, imageToWebp, videoToWebp, writeExif, webp2mp4File }; 222 | -------------------------------------------------------------------------------- /system/main.js: -------------------------------------------------------------------------------- 1 | import "../storage/config.js"; 2 | import { Client, Serialize } from "./lib/serialize.js"; 3 | import Database from "./lib/database.js"; 4 | 5 | import fs from "fs"; 6 | import util from "util"; 7 | import path from "path"; 8 | import pino from "pino"; 9 | import chalk from "chalk"; 10 | import readline from "readline"; 11 | import chokidar from "chokidar"; 12 | import syntaxerror from "syntax-error"; 13 | import { Boom } from "@hapi/boom"; 14 | import NodeCache from "node-cache"; 15 | import baileys, { jidNormalizedUser } from "@whiskeysockets/baileys"; 16 | import { 17 | plugins, 18 | loadPluginFiles, 19 | reload, 20 | pluginFolder, 21 | pluginFilter, 22 | } from "./lib/plugins.js"; 23 | 24 | const logger = pino({ 25 | level: "fatal", 26 | timestamp: () => `,"time":"${new Date().toJSON()}"`, 27 | }).child({ level: "fatal", class: "conn" }); 28 | 29 | const store = baileys.makeInMemoryStore({ logger }); 30 | const rl = readline.createInterface({ 31 | input: process.stdin, 32 | output: process.stdout, 33 | }); 34 | const question = (text) => new Promise((resolve) => rl.question(text, resolve)); 35 | const database = new Database(); 36 | 37 | import { platform } from "process"; 38 | import { fileURLToPath, pathToFileURL } from "url"; 39 | import { createRequire } from "module"; // Bring in the ability to create the 'require' method 40 | global.__filename = function filename( 41 | pathURL = import.meta.url, 42 | rmPrefix = platform !== "win32", 43 | ) { 44 | return rmPrefix 45 | ? /file:\/\/\//.test(pathURL) 46 | ? fileURLToPath(pathURL) 47 | : pathURL 48 | : pathToFileURL(pathURL).toString(); 49 | }; 50 | global.__dirname = function dirname(pathURL) { 51 | return path.dirname(global.__filename(pathURL, true)); 52 | }; 53 | global.__require = function require(dir = import.meta.url) { 54 | return createRequire(dir); 55 | }; 56 | 57 | async function start() { 58 | process.on("uncaughtException", (err) => console.error(err)); 59 | process.on("unhandledRejection", (err) => console.error(err)); 60 | 61 | global.db = database.db; 62 | await database.loadDatabase(); 63 | 64 | const msgRetryCounterCache = new NodeCache(); 65 | const { state, saveCreds } = 66 | await baileys.useMultiFileAuthState("./system/session"); 67 | const conn = baileys.default({ 68 | logger, 69 | printQRInTerminal: false, 70 | auth: { 71 | creds: state.creds, 72 | keys: baileys.makeCacheableSignalKeyStore( 73 | state.keys, 74 | pino({ level: "fatal" }).child({ level: "fatal" }), 75 | ), 76 | }, 77 | browser: ["Ubuntu", "Chrome", "20.0.04"], 78 | markOnlineOnConnect: true, 79 | generateHighQualityLinkPreview: true, 80 | getMessage: async (key) => { 81 | let jid = baileys.jidNormalizedUser(key.remoteJid); 82 | let msg = await store.loadMessage(jid, key.id); 83 | 84 | return msg?.message || ""; 85 | }, 86 | msgRetryCounterCache, 87 | defaultQueryTimeoutMs: undefined, 88 | }); 89 | 90 | store.bind(conn.ev); 91 | 92 | await Client({ conn, store }); 93 | global.conn = conn; 94 | 95 | loadPluginFiles(pluginFolder, pluginFilter, { 96 | logger: conn.logger, 97 | recursiveRead: true, 98 | }) 99 | .then((_) => console.log(Object.keys(plugins))) 100 | .catch(console.error); 101 | 102 | if (!conn.authState.creds.registered) { 103 | let phoneNumber; 104 | 105 | if (!!global.pairingNumber) { 106 | phoneNumber = global.pairingNumber.replace(/[^0-9]/g, ""); 107 | } else { 108 | phoneNumber = await question( 109 | chalk.bgBlack(chalk.greenBright("Please type your WhatsApp number : ")), 110 | ); 111 | phoneNumber = phoneNumber.replace(/[^0-9]/g, ""); 112 | 113 | if ( 114 | !Object.keys(baileys.PHONENUMBER_MCC).some((v) => 115 | phoneNumber.startsWith(v), 116 | ) 117 | ) { 118 | console.log( 119 | chalk.bgBlack( 120 | chalk.redBright( 121 | "Start with your country's WhatsApp code, Example : 62xxx", 122 | ), 123 | ), 124 | ); 125 | 126 | phoneNumber = await question( 127 | chalk.bgBlack( 128 | chalk.greenBright("Please type your WhatsApp number : "), 129 | ), 130 | ); 131 | phoneNumber = phoneNumber.replace(/[^0-9]/g, ""); 132 | rl.close(); 133 | } 134 | } 135 | 136 | setTimeout(async () => { 137 | let code = await conn.requestPairingCode(phoneNumber); 138 | code = code?.match(/.{1,4}/g)?.join("-") || code; 139 | console.log( 140 | chalk.black(chalk.bgGreen("Your Pairing Code : ")), 141 | chalk.black(chalk.white(code)), 142 | ); 143 | }, 3000); 144 | } 145 | 146 | conn.ev.on("connection.update", async (update) => { 147 | const { lastDisconnect, connection, qr } = update; 148 | 149 | if (connection) conn.logger.info(`Connection Status : ${connection}`); 150 | if (connection === "close") { 151 | let reason = new Boom(lastDisconnect?.error)?.output.statusCode; 152 | 153 | if (reason === baileys.DisconnectReason.badSession) { 154 | console.log("File Sesi Rusak, Harap Hapus Sesi dan Pindai Lagi"); 155 | process.send("reset"); 156 | } else if (reason === baileys.DisconnectReason.connectionClosed) { 157 | console.log("Koneksi ditutup, menyambung kembali...."); 158 | await start(); 159 | } else if (reason === baileys.DisconnectReason.connectionLost) { 160 | console.log("Koneksi Hilang dari Server, menyambung kembali..."); 161 | await start(); 162 | } else if (reason === baileys.DisconnectReason.connectionReplaced) { 163 | console.log( 164 | "Koneksi Diganti, Sesi Baru Dibuka, Harap Tutup Sesi Saat Ini Terlebih Dahulu", 165 | ); 166 | process.exit(1); 167 | } else if (reason === baileys.DisconnectReason.loggedOut) { 168 | console.log("Perangkat Keluar, Silakan Pindai Lagi"); 169 | process.exit(1); 170 | } else if (reason === baileys.DisconnectReason.restartRequired) { 171 | console.log("Diperlukan Mulai Ulang, Mulai Ulang..."); 172 | await start(); 173 | } else if (reason === baileys.DisconnectReason.timedOut) { 174 | console.log("Waktu Sambungan Habis, Mulai Ulang..."); 175 | process.send("reset"); 176 | } else if (reason === baileys.DisconnectReason.multideviceMismatch) { 177 | console.log("Ketidakcocokan multi perangkat, harap pindai lagi"); 178 | process.exit(0); 179 | } else { 180 | console.log(reason); 181 | process.send("reset"); 182 | } 183 | } 184 | 185 | if (connection === "open") { 186 | conn.logger.info("Connecting Success..."); 187 | } 188 | }); 189 | 190 | conn.ev.on("creds.update", saveCreds); 191 | 192 | // add contacts update to store 193 | conn.ev.on("contacts.update", (update) => { 194 | for (let contact of update) { 195 | let id; 196 | try { 197 | id = jidNormalizedUser(contact.id); 198 | if (!id) { 199 | console.error( 200 | `jidNormalizedUser failed or returned undefined for contact id: ${contact.id}`, 201 | ); 202 | continue; 203 | } 204 | } catch (error) { 205 | console.error( 206 | `Error normalizing JID for contact id: ${contact.id}`, 207 | error, 208 | ); 209 | continue; 210 | } 211 | 212 | if (store && store.contacts) { 213 | if (!store.contacts[id]) { 214 | console.warn( 215 | `No existing contact found for id: ${id}. Creating new contact entry.`, 216 | ); 217 | } 218 | 219 | store.contacts[id] = { 220 | ...(store.contacts?.[id] || {}), 221 | ...(contact || {}), 222 | }; 223 | } 224 | } 225 | }); 226 | 227 | // add contacts upsert to store 228 | conn.ev.on("contacts.upsert", (update) => { 229 | for (let contact of update) { 230 | let id = jidNormalizedUser(contact.id); 231 | if (store && store.contacts) 232 | store.contacts[id] = { ...(contact || {}), isContact: true }; 233 | } 234 | }); 235 | 236 | // nambah perubahan grup ke store 237 | conn.ev.on("groups.update", (updates) => { 238 | for (const update of updates) { 239 | const id = update.id; 240 | if (store.groupMetadata[id]) { 241 | store.groupMetadata[id] = { 242 | ...(store.groupMetadata[id] || {}), 243 | ...(update || {}), 244 | }; 245 | } 246 | } 247 | }); 248 | 249 | conn.ev.on("messages.upsert", async (message) => { 250 | if (!message.messages) return; 251 | 252 | const m = await Serialize(conn, message.messages[0]); 253 | 254 | if (store.groupMetadata && Object.keys(store.groupMetadata).length === 0) 255 | store.groupMetadata = await client.groupFetchAllParticipating(); 256 | 257 | await ( 258 | await import(`./handler.js?v=${Date.now()}`) 259 | ).handler(conn, m, message); 260 | }); 261 | 262 | conn.ev.on("group-participants.update", async (message) => { 263 | await ( 264 | await import(`./handler.js?v=${Date.now()}`) 265 | ).participantsUpdate(message); 266 | }); 267 | 268 | conn.ev.on("groups.update", async (update) => { 269 | await (await import(`./handler.js?v=${Date.now()}`)).groupsUpdate(update); 270 | }); 271 | 272 | conn.ev.on("call", async (json) => { 273 | await (await import(`./handler.js?v=${Date.now()}`)).rejectCall(json); 274 | }); 275 | 276 | conn.ev.on("presence.update", async (presenceUpdateEvent) => { 277 | try { 278 | await ( 279 | await import(`./handler.js?v=${Date.now()}`) 280 | ).presenceUpdate(presenceUpdateEvent); 281 | } catch (error) { 282 | console.error("Error handling presence update:", error); 283 | } 284 | }); 285 | 286 | setInterval(async () => { 287 | if (global.db.data) await global.db.write().catch(console.error); 288 | }, 60 * 1000); 289 | 290 | return conn; 291 | } 292 | 293 | start(); 294 | -------------------------------------------------------------------------------- /system/handler.js: -------------------------------------------------------------------------------- 1 | import * as os from "os"; 2 | import path from "path"; 3 | import chalk from "chalk"; 4 | import fs from "fs"; 5 | import { exec } from "child_process"; 6 | import { fileURLToPath } from "url"; 7 | import { createRequire } from "module"; 8 | import baileys, { delay } from "@whiskeysockets/baileys"; 9 | import { plugins } from "./lib/plugins.js"; 10 | // Utility function to check if a value is a number 11 | const isNumber = (x) => typeof x === "number" && !isNaN(x); 12 | 13 | // Initialize the database 14 | const database = new (await import("./lib/database.js")).default(); 15 | 16 | global.plugins = plugins; 17 | 18 | export async function handler(conn, m, chatUpdate) { 19 | conn.msgqueque = conn.msgqueque || []; 20 | if (!m || typeof m !== "object") return; 21 | 22 | try { 23 | await database.load(m, db); 24 | } catch (e) { 25 | conn.logger.error("Database loader Error: ", e); 26 | } 27 | 28 | try { 29 | m.exp = 0; 30 | m.limit = false; 31 | 32 | const isPrems = m.isOwner || db.data.users[m.sender]?.premium; 33 | 34 | if (!m.isOwner && db.data.settings.self) return; 35 | if (db.data.settings.pconly && m.chat.endsWith("g.us")) return; 36 | if (db.data.settings.gconly && !m.chat.endsWith("g.us")) return; 37 | if (db.data.settings.autoread) conn.readMessages([m.key]); 38 | if (m.isBaileys) return; 39 | 40 | // Message queue handling 41 | if (db.data.settings.queque && m.body && !isPrems) { 42 | let queque = conn.msgqueque, 43 | time = 1000 * 5; 44 | let previousID = queque[queque.length - 1]; 45 | 46 | queque.push(m.id || m.key.id); 47 | setInterval(async () => { 48 | if (queque.indexOf(previousID) === -1) clearInterval(conn); 49 | await delay(time); 50 | }, time); 51 | } 52 | 53 | // Assign experience points 54 | m.exp += Math.ceil(Math.random() * 10); 55 | let user = db.users && db.users[m.sender]; 56 | 57 | for (let name in plugins) { 58 | let plugin = plugins[name]; 59 | 60 | if (!plugin) continue; 61 | if (plugin.disabled) continue; 62 | if (typeof plugin.all === "function") { 63 | try { 64 | await plugin.all.call(conn, m, { chatUpdate }); 65 | } catch (e) { 66 | console.error(e); 67 | } 68 | } 69 | 70 | if (typeof plugin.before === "function") { 71 | if (await plugin.before.call(conn, m, { chatUpdate })) continue; 72 | } 73 | 74 | if (m.prefix) { 75 | let { args, text } = m; 76 | let isCommand = (m.prefix && m.body.startsWith(m.prefix)) || false; 77 | const command = isCommand ? m.command.toLowerCase() : false; 78 | 79 | let isAccept = Array.isArray(plugin.command) 80 | ? plugin.command.some((cmd) => cmd === command) 81 | : false; 82 | 83 | m.plugin = name; 84 | if (!isAccept) continue; 85 | if (m.chat in db.data.chats || m.sender in db.data.users) { 86 | if (!m.isOwner && db.data.chats[m.chat]?.isBanned) return; 87 | if (!m.isOwner && db.data.users[m.sender]?.banned) return; 88 | } 89 | 90 | if (plugin.owner && !m.isOwner) { 91 | m.reply("owner"); 92 | continue; 93 | } 94 | 95 | if (plugin.premium && !isPrems) { 96 | m.reply("premium"); 97 | continue; 98 | } 99 | 100 | if (plugin.group && !m.isGroup) { 101 | m.reply("group"); 102 | continue; 103 | } 104 | 105 | if (plugin.botAdmin && !m.isBotAdmin) { 106 | m.reply("botAdmin"); 107 | continue; 108 | } 109 | 110 | if (plugin.admin && !m.isAdmin) { 111 | m.reply("admin"); 112 | continue; 113 | } 114 | 115 | if (plugin.private && m.isGroup) { 116 | m.reply("private"); 117 | continue; 118 | } 119 | 120 | if (plugin.register && !user?.registered) { 121 | m.reply("register"); 122 | continue; 123 | } 124 | 125 | if (plugin.quoted && !m.isQuoted) { 126 | m.reply("quoted"); 127 | continue; 128 | } 129 | 130 | m.isCommand = true; 131 | let xp = "exp" in plugin ? parseInt(plugin.exp) : 3; 132 | 133 | if (xp < 200) m.exp += xp; 134 | if (plugin.loading) m.reply("wait"); 135 | if (plugin.limit && user.limit < 1 && !isPrems) { 136 | m.reply("limit"); 137 | continue; 138 | } 139 | 140 | if (plugin.example && !text) { 141 | m.reply( 142 | plugin.example 143 | .replace(/%p/gi, m.prefix) 144 | .replace(/%cmd/gi, plugin.name) 145 | .replace(/%text/gi, text), 146 | ); 147 | continue; 148 | } 149 | 150 | let extra = { 151 | conn, 152 | args, 153 | isPrems, 154 | command, 155 | text, 156 | chatUpdate, 157 | }; 158 | 159 | try { 160 | await plugin.run(m, extra); 161 | } catch (e) { 162 | console.error(e); 163 | m.reply(func.format(e)); 164 | } finally { 165 | if (typeof plugin.after === "function") { 166 | try { 167 | await plugin.after.call(conn, m, extra); 168 | } catch (e) { 169 | console.error(e); 170 | } 171 | } 172 | } 173 | } 174 | } 175 | } catch (e) { 176 | console.error(e); 177 | } finally { 178 | if (db.data.settings.queque && m.body) { 179 | let quequeIndex = conn.msgqueque.indexOf(m.id || m.key.id); 180 | if (quequeIndex !== -1) conn.msgqueque.splice(quequeIndex, 1); 181 | } 182 | 183 | if (m) { 184 | let user, 185 | stats = db.data.stats, 186 | stat; 187 | if (m.sender && (user = db.data.users[m.sender])) { 188 | user.exp += m.exp; 189 | user.limit -= m.limit * 1; 190 | } 191 | 192 | if (m.plugin) { 193 | if (m.plugin in stats) { 194 | stat = stats[m.plugin]; 195 | if (!isNumber(stat.total)) stat.total = 1; 196 | if (!isNumber(stat.success)) stat.success = m.error != null ? 0 : 1; 197 | if (!isNumber(stat.last)) stat.last = +new Date(); 198 | if (!isNumber(stat.lastSuccess)) 199 | stat.lastSuccess = m.error != null ? 0 : +new Date(); 200 | } else { 201 | stat = stats[m.plugin] = { 202 | total: 1, 203 | success: m.error != null ? 0 : 1, 204 | last: +new Date(), 205 | lastSuccess: m.error != null ? 0 : +new Date(), 206 | }; 207 | } 208 | stat.total += 1; 209 | stat.last = +new Date(); 210 | if (m.error == null) { 211 | stat.success += 1; 212 | stat.lastSuccess = +new Date(); 213 | } 214 | } 215 | } 216 | 217 | if (!m.isBaileys && !m.fromMe) 218 | console.log( 219 | "~> [\x1b[1;32m CMD \x1b[1;37m]", 220 | chalk.yellow(m.type), 221 | "from", 222 | chalk.green(m.pushName), 223 | "in", 224 | chalk.cyan(m.isGroup ? m.metadata.subject : "private chat"), 225 | "args :", 226 | chalk.green(m.body?.length || 0), 227 | ); 228 | } 229 | } 230 | 231 | export async function participantsUpdate({ id, participants, action }) { 232 | if (db.data.settings.self) return; 233 | 234 | let chat = db.data.chats[id] || {}, 235 | ppuser; 236 | let metadata = await conn.groupMetadata(id); 237 | 238 | switch (action) { 239 | case "add": 240 | case "remove": 241 | if (chat.welcome) { 242 | for (let user of participants) { 243 | try { 244 | ppuser = await conn.profilePictureUrl(user, "image"); 245 | } catch { 246 | ppuser = 247 | "https://i0.wp.com/www.gambarunik.id/wp-content/uploads/2019/06/Top-Gambar-Foto-Profil-Kosong-Lucu-Tergokil-.jpg"; 248 | } finally { 249 | let tekswell = `Halo @${ 250 | user.split("@")[0] 251 | } 👋\n\nSelamat datang di grup ${ 252 | metadata.subject 253 | }! Kami senang kamu bergabung dengan kami.\n\nSaya harap kamu betah disini dan jangan lupa untuk selalu mengikuti peraturan yang ada`; 254 | let teksbye = `Selamat tinggal @${ 255 | user.split("@")[0] 256 | } 👋\n\nSalam perpisahan, kami harap kamu baik-baik saja disana`; 257 | 258 | if (action == "add") { 259 | conn.sendMessage(id, { 260 | image: { url: ppuser }, 261 | contextInfo: { mentionedJid: [user] }, 262 | caption: tekswell, 263 | mentions: [user], 264 | }); 265 | } else if (action == "remove") { 266 | conn.sendMessage(id, { text: teksbye, mentions: [user] }); 267 | } 268 | } 269 | } 270 | } 271 | break; 272 | case "promote": 273 | case "demote": 274 | let tekspro = `Selamat @${ 275 | participants[0].split("@")[0] 276 | } atas kenaikan pangkatnya di grup ${metadata.subject} 🥂`; 277 | let teksdem = `Sabar yaa @${ 278 | participants[0].split("@")[0] 279 | } atas penurunan pangkatnya di grup ${metadata.subject} 😔`; 280 | 281 | if (chat.detect) { 282 | if (action == "promote") 283 | conn.sendMessage(id, { text: tekspro, mentions: [participants[0]] }); 284 | if (action == "demote") 285 | conn.sendMessage(id, { text: teksdem, mentions: [participants[0]] }); 286 | } 287 | break; 288 | } 289 | } 290 | 291 | export async function groupsUpdate(groupsUpdate) { 292 | if (db.data.settings.self) return; 293 | for (let groupUpdate of groupsUpdate) { 294 | let id = groupUpdate.id; 295 | let chats = db.data.chats[id] || {}, 296 | text = ""; 297 | 298 | if (!chats.detect) continue; 299 | if (groupUpdate.desc) 300 | text = "*Deskripsi grup telah diubah menjadi*\n\n@desc".replace( 301 | "@desc", 302 | groupUpdate.desc, 303 | ); 304 | if (groupUpdate.subject) 305 | text = "*Judul grup telah diubah menjadi*\n\n@subject".replace( 306 | "@subject", 307 | groupUpdate.subject, 308 | ); 309 | if (groupUpdate.icon) text = "*Ikon grup telah diubah*"; 310 | if (groupUpdate.inviteCode) 311 | text = 312 | "*Tautan grup telah diubah menjadi*\n\nhttps://chat.whatsapp.com/@revoke".replace( 313 | "@revoke", 314 | groupUpdate.inviteCode, 315 | ); 316 | if (groupUpdate.announce === true) text = "*Grup telah ditutup*"; 317 | if (groupUpdate.announce === false) text = "*Grup telah dibuka*"; 318 | if (groupUpdate.restrict === true) 319 | text = "*Grup dibatasi hanya untuk peserta saja*"; 320 | if (groupUpdate.restrict === false) 321 | text = "*Grup ini dibatasi hanya untuk admin saja*"; 322 | 323 | conn.sendMessage(id, { text }); 324 | } 325 | } 326 | 327 | export async function deleteUpdate({ fromMe, id, participants }) { 328 | try { 329 | if (fromMe) return; 330 | let msg = conn.serializeM(conn.loadMessage(id)); 331 | if (!msg) return; 332 | if (db.data.chats[m.chat].antidelete) return; 333 | 334 | conn.sendMessage( 335 | msg.key.remoteJid, 336 | { 337 | text: `[❗] Terdeteksi @${ 338 | participants[0].split("@")[0] 339 | } telah menghapus pesan.\n\nUntuk mematikan fitur ini, ketik *.off antidelete*\nUntuk menghapus pesan yang dikirim oleh BOT, balas pesan dengan perintah *.delete*`, 340 | mentions: [participants[0]], 341 | }, 342 | { quoted: msg }, 343 | ); 344 | conn.copyNForward(m.chat, msg, false); 345 | } catch (e) { 346 | console.error(e); 347 | } 348 | } 349 | 350 | export async function presenceUpdate(presenceUpdate) { 351 | const id = presenceUpdate.id; 352 | const nouser = Object.keys(presenceUpdate.presences); 353 | const status = presenceUpdate.presences[nouser]?.lastKnownPresence; 354 | const user = db.data.users[nouser[0]]; 355 | 356 | if (user?.afk && status === "composing" && user.afk > -1) { 357 | if (user.banned) { 358 | user.afk = -1; 359 | user.afkReason = "User Banned AFK"; 360 | return; 361 | } 362 | 363 | const username = nouser[0].split("@")[0]; 364 | const timeAfk = new Date() - user.afk; 365 | const caption = `@${username} berhenti afk, dia sedang mengetik\n\nAlasan: ${ 366 | user.afkReason ? user.afkReason : "tidak ada alasan" 367 | }\nSelama: ${timeAfk.toTimeString()} yang lalu`; 368 | 369 | conn.sendMessage(id, { text: caption }); 370 | user.afk = -1; 371 | user.afkReason = ""; 372 | } 373 | } 374 | 375 | export async function rejectCall(json) { 376 | if (db.data.settings.anticall) { 377 | for (let id of json) { 378 | if (id.status === "offer") { 379 | let msg = await conn.sendMessage(id.from, { 380 | text: "Maaf untuk saat ini, Kami tidak dapat menerima panggilan, entah dalam group atau pribadi\n\nJika Membutuhkan bantuan ataupun request fitur silahkan chat owner", 381 | }); 382 | 383 | conn.sendContact(id.from, global.owner, msg); 384 | await conn.rejectCall(id.id, id.from); 385 | } 386 | } 387 | } 388 | } 389 | 390 | let file = fileURLToPath(import.meta.url); 391 | 392 | fs.watchFile(file, () => { 393 | fs.unwatchFile(file); 394 | console.log(`Update ${file}`); 395 | import(file); 396 | }); 397 | -------------------------------------------------------------------------------- /system/lib/function.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import Jimp from "jimp"; 4 | import axios from "axios"; 5 | import chalk from "chalk"; 6 | import cheerio from "cheerio"; 7 | import { format } from "util"; 8 | import { platform } from "os"; 9 | import term from "terminal-kit"; 10 | import mimes from "mime-types"; 11 | import FormData from "form-data"; 12 | import { exec } from "child_process"; 13 | import moment from "moment-timezone"; 14 | import baileys from "@whiskeysockets/baileys"; 15 | import { fileTypeFromBuffer } from "file-type"; 16 | import { fileURLToPath, pathToFileURL } from "url"; 17 | 18 | export default new (class Function { 19 | constructor() { 20 | this.axios = axios; 21 | this.cheerio = cheerio; 22 | this.fs = fs; 23 | this.path = path; 24 | this.baileys = baileys; 25 | this.FormData = FormData; 26 | this.upload = { 27 | telegra: this.telegra.bind(this), 28 | pomf: this.pomf.bind(this), 29 | hari: this.hari.bind(this), 30 | tmp: this.tmp.bind(this), 31 | freeimage: this.freeimage.bind(this), 32 | }; 33 | } 34 | 35 | __filename(pathURL = import.meta, rmPrefix = platform() !== "win32") { 36 | const path = pathURL?.url || pathURL; 37 | 38 | return rmPrefix 39 | ? /file:\/\/\//.test(path) 40 | ? fileURLToPath(path) 41 | : path 42 | : /file:\/\/\//.test(path) 43 | ? path 44 | : pathToFileURL(path).href; 45 | } 46 | 47 | __dirname(pathURL) { 48 | const dir = this.__filename(pathURL, true); 49 | const regex = /\/$/; 50 | 51 | return regex.test(dir) 52 | ? dir 53 | : fs.existsSync(dir) && fs.statSync(dir).isDirectory 54 | ? dir.replace(regex, "") 55 | : path.dirname(dir); 56 | } 57 | 58 | async dirSize(directory) { 59 | const files = await fs.readdirSync(directory); 60 | const stats = files.map((file) => fs.statSync(path.join(directory, file))); 61 | 62 | return (await Promise.all(stats)).reduce( 63 | (accumulator, { size }) => accumulator + size, 64 | 0, 65 | ); 66 | } 67 | 68 | sleep(ms) { 69 | return new Promise((a) => setTimeout(a, ms)); 70 | } 71 | 72 | format(str) { 73 | return format(str); 74 | } 75 | 76 | Format(str) { 77 | return JSON.stringify(str, null, 2); 78 | } 79 | 80 | jam(numer, options = {}) { 81 | let format = options.format ? options.format : "HH:mm"; 82 | let jam = options?.timeZone 83 | ? moment(numer).tz(options.timeZone).format(format) 84 | : moment(numer).format(format); 85 | 86 | return `${jam}`; 87 | } 88 | 89 | tanggal(numer, timeZone = "") { 90 | const myMonths = [ 91 | "Januari", 92 | "Februari", 93 | "Maret", 94 | "April", 95 | "Mei", 96 | "Juni", 97 | "Juli", 98 | "Agustus", 99 | "September", 100 | "Oktober", 101 | "November", 102 | "Desember", 103 | ]; 104 | const myDays = [ 105 | "Minggu", 106 | "Senin", 107 | "Selasa", 108 | "Rabu", 109 | "Kamis", 110 | "Jum’at", 111 | "Sabtu", 112 | ]; 113 | var tgl = new Date(numer); 114 | timeZone ? tgl.toLocaleString("en", { timeZone }) : ""; 115 | var day = tgl.getDate(); 116 | var bulan = tgl.getMonth(); 117 | var thisDay = tgl.getDay(), 118 | thisDay = myDays[thisDay]; 119 | var yy = tgl.getYear(); 120 | var year = yy < 1000 ? yy + 1900 : yy; 121 | 122 | return `${thisDay}, ${day} ${myMonths[bulan]} ${year}`; 123 | } 124 | 125 | async getFile(PATH, save) { 126 | try { 127 | let filename = null; 128 | let data = await this.fetchBuffer(PATH); 129 | 130 | if (data?.data && save) { 131 | filename = path.join( 132 | process.cwd(), 133 | "storage/tmp", 134 | Date.now() + "." + data.ext, 135 | ); 136 | fs.promises.writeFile(filename, data?.data); 137 | } 138 | return { 139 | filename: data?.name ? data.name : filename, 140 | ...data, 141 | }; 142 | } catch (e) { 143 | throw e; 144 | } 145 | } 146 | 147 | async fetchJson(url, options = {}) { 148 | try { 149 | let data = await axios.get(url, { 150 | headers: { 151 | ...(!!options.headers ? options.headers : {}), 152 | }, 153 | responseType: "json", 154 | ...options, 155 | }); 156 | 157 | return await data?.data; 158 | } catch (e) { 159 | throw e; 160 | } 161 | } 162 | 163 | fetchBuffer(string, options = {}) { 164 | return new Promise(async (resolve, reject) => { 165 | try { 166 | if (/^https?:\/\//i.test(string)) { 167 | let data = await axios.get(string, { 168 | headers: { 169 | ...(!!options.headers ? options.headers : {}), 170 | }, 171 | responseType: "arraybuffer", 172 | ...options, 173 | }); 174 | 175 | let buffer = await data?.data; 176 | let name = /filename/i.test(data.headers?.get("content-disposition")) 177 | ? data.headers 178 | ?.get("content-disposition") 179 | ?.match(/filename=(.*)/)?.[1] 180 | ?.replace(/[""]/g, "") 181 | : ""; 182 | let mime = 183 | mimes.lookup(name) || 184 | data.headers.get("content-type") || 185 | (await fileTypeFromBuffer(buffer))?.mime; 186 | 187 | resolve({ 188 | data: buffer, 189 | size: Buffer.byteLength(buffer), 190 | sizeH: this.formatSize(Buffer.byteLength(buffer)), 191 | name, 192 | mime, 193 | ext: mimes.extension(mime), 194 | }); 195 | } else if (/^data:.*?\/.*?base64,/i.test(string)) { 196 | let data = Buffer.from(string.split`,`[1], "base64"); 197 | let size = Buffer.byteLength(data); 198 | 199 | resolve({ 200 | data, 201 | size, 202 | sizeH: this.formatSize(size), 203 | ...((await fileTypeFromBuffer(data)) || { 204 | mime: "application/octet-stream", 205 | ext: ".bin", 206 | }), 207 | }); 208 | } else if (fs.existsSync(string) && fs.statSync(string).isFile()) { 209 | let data = fs.readFileSync(string); 210 | let size = Buffer.byteLength(data); 211 | 212 | resolve({ 213 | data, 214 | size, 215 | sizeH: this.formatSize(size), 216 | ...((await fileTypeFromBuffer(data)) || { 217 | mime: "application/octet-stream", 218 | ext: ".bin", 219 | }), 220 | }); 221 | } else if (Buffer.isBuffer(string)) { 222 | let size = Buffer?.byteLength(string) || 0; 223 | 224 | resolve({ 225 | data: string, 226 | size, 227 | sizeH: this.formatSize(size), 228 | ...((await fileTypeFromBuffer(string)) || { 229 | mime: "application/octet-stream", 230 | ext: ".bin", 231 | }), 232 | }); 233 | } else if (/^[a-zA-Z0-9+/]={0,2}$/i.test(string)) { 234 | let data = Buffer.from(string, "base64"); 235 | let size = Buffer.byteLength(data); 236 | 237 | resolve({ 238 | data, 239 | size, 240 | sizeH: this.formatSize(size), 241 | ...((await fileTypeFromBuffer(data)) || { 242 | mime: "application/octet-stream", 243 | ext: ".bin", 244 | }), 245 | }); 246 | } else { 247 | let buffer = Buffer.alloc(20); 248 | let size = Buffer.byteLength(buffer); 249 | 250 | resolve({ 251 | data: buffer, 252 | size, 253 | sizeH: this.formatSize(size), 254 | ...((await fileTypeFromBuffer(buffer)) || { 255 | mime: "application/octet-stream", 256 | ext: ".bin", 257 | }), 258 | }); 259 | } 260 | } catch (e) { 261 | reject(new Error(e?.message || e)); 262 | } 263 | }); 264 | } 265 | 266 | mime(name) { 267 | let mimetype = mimes.lookup(name); 268 | if (!mimetype) return mimes.extension(name); 269 | return { mime: mimetype, ext: mimes.extension(mimetype) }; 270 | } 271 | 272 | isUrl(url) { 273 | let regex = new RegExp( 274 | /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/, 275 | "gi", 276 | ); 277 | if (!regex.test(url)) return false; 278 | return url.match(regex); 279 | } 280 | 281 | escapeRegExp(string) { 282 | return string.replace(/[.*=+:\-?^${}()|[\]\\]|\s/g, "\\$&"); 283 | } 284 | 285 | toUpper(query) { 286 | const arr = query.split(" "); 287 | for (var i = 0; i < arr.length; i++) { 288 | arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1); 289 | } 290 | 291 | return arr.join(" "); 292 | } 293 | 294 | getRandom(ext = "", length = "10") { 295 | var result = ""; 296 | var character = 297 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; 298 | var characterLength = character.length; 299 | 300 | for (var i = 0; i < length; i++) { 301 | result += character.charAt(Math.floor(Math.random() * characterLength)); 302 | } 303 | 304 | return `${result}${ext ? `.${ext}` : ""}`; 305 | } 306 | 307 | formatSize(bytes, si = true, dp = 2) { 308 | const thresh = si ? 1000 : 1024; 309 | 310 | if (Math.abs(bytes) < thresh) { 311 | return `${bytes} B`; 312 | } 313 | 314 | const units = si 315 | ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] 316 | : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; 317 | const r = 10 ** dp; 318 | let u = -1; 319 | 320 | do { 321 | bytes /= thresh; 322 | ++u; 323 | } while ( 324 | Math.round(Math.abs(bytes) * r) / r >= thresh && 325 | u < units.length - 1 326 | ); 327 | 328 | return `${bytes.toFixed(dp)} ${units[u]}`; 329 | } 330 | 331 | async resizeImage(buffer, height) { 332 | buffer = (await this.getFile(buffer)).data; 333 | 334 | return new Promise((resolve, reject) => { 335 | Jimp.read(buffer, (err, image) => { 336 | if (err) { 337 | reject(err); 338 | return; 339 | } 340 | 341 | image 342 | .resize(Jimp.AUTO, height) 343 | .getBuffer(Jimp.MIME_PNG, (err, resizedBuffer) => { 344 | if (err) { 345 | reject(err); 346 | return; 347 | } 348 | resolve(resizedBuffer); 349 | }); 350 | }); 351 | }); 352 | } 353 | 354 | runtime(seconds) { 355 | seconds = Number(seconds); 356 | var d = Math.floor(seconds / (3600 * 24)); 357 | var h = Math.floor((seconds % (3600 * 24)) / 3600); 358 | var m = Math.floor((seconds % 3600) / 60); 359 | var s = Math.floor(seconds % 60); 360 | var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : ""; 361 | var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : ""; 362 | var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : ""; 363 | var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : ""; 364 | return dDisplay + hDisplay + mDisplay + sDisplay; 365 | } 366 | 367 | loading() { 368 | var { terminal } = term; 369 | var progressBar, 370 | progress = 0; 371 | 372 | function doProgress() { 373 | progress += Math.random() / 10; 374 | progressBar.update(progress); 375 | if (progress >= 1) { 376 | setTimeout(function () { 377 | console.clear(), 378 | exec(`screenfetch - A Deepin`, (error, stdout, stderr) => { 379 | console.log(stdout), 380 | console.log(chalk.bgGray("Bot WhatsApp By Alisa & Ahyad")); 381 | }); 382 | }, 200); 383 | } else { 384 | setTimeout(doProgress, 90 + Math.random() * 200); 385 | } 386 | } 387 | 388 | progressBar = terminal.progressBar({ 389 | width: 80, 390 | title: "\n\nLoad this script....", 391 | eta: true, 392 | percent: true, 393 | }); 394 | 395 | doProgress(); 396 | } 397 | 398 | reloadPlugin(type, file) { 399 | const filename = (file) => file.replace(/^.*[\\\/]/, ""); 400 | 401 | switch (type) { 402 | case "delete": 403 | return delete global.plugins[file]; 404 | break; 405 | case "add": 406 | case "change": 407 | try { 408 | (async () => { 409 | const module = await import(`${file}?update=${Date.now()}`); 410 | global.plugins[file] = module.default || module; 411 | })(); 412 | } catch (e) { 413 | conn.logger.error( 414 | `Error require plugin "${filename(file)}\n${format(e)}"`, 415 | ); 416 | } finally { 417 | global.plugins = Object.fromEntries( 418 | Object.entries(global.plugins).sort(([a], [b]) => 419 | a.localeCompare(b), 420 | ), 421 | ); 422 | } 423 | break; 424 | } 425 | } 426 | 427 | timeSpeech() { 428 | let ucapanWaktu = ""; 429 | let wakt = moment.tz("Asia/Jakarta").format("HH:mm"); 430 | 431 | if (wakt < "23:59") ucapanWaktu = "Selamat Malam"; 432 | if (wakt < "19:00") ucapanWaktu = "Selamat Petang"; 433 | if (wakt < "18:00") ucapanWaktu = "Selamat Sore"; 434 | if (wakt < "15:00") ucapanWaktu = "Selamat Siang"; 435 | if (wakt < "10:00") ucapanWaktu = "Selamat Pagi"; 436 | if (wakt < "05:00") ucapanWaktu = "Selamat Subuh"; 437 | if (wakt < "03:00") ucapanWaktu = "Selamat Tengah Malam"; 438 | 439 | return ucapanWaktu; 440 | } 441 | 442 | pomf(media) { 443 | return new Promise(async (resolve, reject) => { 444 | let mime = await fileTypeFromBuffer(media); 445 | let form = new FormData(); 446 | 447 | form.append("files[]", media, `file-${Date.now()}.${mime.ext}`); 448 | 449 | axios 450 | .post("https://pomf.lain.la/upload.php", form, { 451 | headers: { 452 | "User-Agent": 453 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", 454 | ...form.getHeaders(), 455 | }, 456 | }) 457 | .then(({ data }) => resolve(data.files[0].url)) 458 | .catch(reject); 459 | }); 460 | } 461 | 462 | telegra(media) { 463 | return new Promise(async (resolve, reject) => { 464 | let mime = await fileTypeFromBuffer(media); 465 | let form = new FormData(); 466 | 467 | form.append("file", media, `file-${Date.now()}.${mime.ext}`); 468 | 469 | axios 470 | .post("https://telegra.ph/upload", form, { 471 | headers: { 472 | "User-Agent": 473 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", 474 | ...form.getHeaders(), 475 | }, 476 | }) 477 | .then(({ data }) => resolve("https://telegra.ph" + data[0].src)) 478 | .catch(reject); 479 | }); 480 | } 481 | 482 | hari(media) { 483 | return new Promise(async (resolve, reject) => { 484 | let mime = await fileTypeFromBuffer(media); 485 | let form = new FormData(); 486 | 487 | form.append("file", media, `file-${Date.now()}.${mime.ext}`); 488 | 489 | axios 490 | .post("https://hari.christmas/upload", form, { 491 | headers: { 492 | "User-Agent": 493 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", 494 | ...form.getHeaders(), 495 | }, 496 | }) 497 | .then(({ data }) => resolve(data.downloadUrl)) 498 | .catch(reject); 499 | }); 500 | } 501 | 502 | tmp(media) { 503 | return new Promise(async (resolve, reject) => { 504 | let mime = await fileTypeFromBuffer(media); 505 | let form = new FormData(); 506 | 507 | form.append("file", media, `file-${Date.now()}.${mime.ext}`); 508 | 509 | axios 510 | .post("https://tmpfiles.org/api/v1/upload", form, { 511 | headers: { 512 | "User-Agent": 513 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", 514 | ...form.getHeaders(), 515 | }, 516 | }) 517 | .then(({ data }) => { 518 | const url = data.data.url.match(/https:\/\/tmpfiles.org\/(.*)/)[1]; 519 | const hasil = "https://tmpfiles.org/dl/" + url; 520 | resolve(hasil); 521 | }) 522 | .catch(reject); 523 | }); 524 | } 525 | 526 | async freeimage(buffer) { 527 | const { data: html } = await axios 528 | .get("https://freeimage.host/") 529 | .catch(() => null); 530 | const token = html.match(/PF.obj.config.auth_token = "(.+?)";/)[1]; 531 | let mime = await fileTypeFromBuffer(buffer); 532 | let form = new FormData(); 533 | 534 | form.append("source", buffer, `file-${Date.now()}.${mime.ext}`); 535 | 536 | const options = { 537 | type: "file", 538 | action: "upload", 539 | timestamp: (Date.now() / 1000).toString(), 540 | auth_token: token, 541 | nsfw: "0", 542 | }; 543 | for (const [key, value] of Object.entries(options)) { 544 | form.append(key, value); 545 | } 546 | const { data } = await axios.post("https://freeimage.host/json", form, { 547 | headers: { 548 | "Content-Type": "multipart/form-data", 549 | }, 550 | }); 551 | return data.image.url; 552 | } 553 | })(); 554 | -------------------------------------------------------------------------------- /system/lib/serialize.js: -------------------------------------------------------------------------------- 1 | import Function from "./function.js"; 2 | import { writeExif } from "./sticker.js"; 3 | 4 | import fs from "fs"; 5 | import util from "util"; 6 | import chalk from "chalk"; 7 | import Crypto from "crypto"; 8 | import baileys from "@whiskeysockets/baileys"; 9 | import { parsePhoneNumber } from "libphonenumber-js"; 10 | 11 | const { 12 | generateWAMessageFromContent, 13 | proto, 14 | prepareWAMessageMedia, 15 | jidNormalizedUser, 16 | WA_DEFAULT_EPHEMERAL, 17 | } = baileys; 18 | 19 | export function Client({ conn, store }) { 20 | delete store.groupMetadata; 21 | 22 | for (let v in store) { 23 | conn[v] = store[v]; 24 | } 25 | 26 | const client = Object.defineProperties(conn, { 27 | appenTextMessage: { 28 | async value(m, text, chatUpdate) { 29 | let messages = await baileys.generateWAMessage( 30 | m.chat, 31 | { text: text, mentions: m.mentionedJid }, 32 | { userJid: conn.user.id, quoted: m.quoted && m.quoted.fakeObj }, 33 | ); 34 | 35 | messages.key.fromMe = baileys.areJidsSameUser(m.sender, conn.user.id); 36 | messages.key.id = m.key.id; 37 | messages.pushName = m.pushName; 38 | 39 | if (m.isGroup) messages.participant = m.sender; 40 | 41 | let msg = { 42 | ...chatUpdate, 43 | messages: [baileys.proto.WebMessageInfo.fromObject(messages)], 44 | type: "append", 45 | }; 46 | 47 | conn.ev.emit("messages.upsert", msg); 48 | }, 49 | }, 50 | 51 | logger: { 52 | get() { 53 | return { 54 | info(...args) { 55 | console.log( 56 | chalk.bold.bgRgb(51, 204, 51)("INFO "), 57 | chalk.cyan(util.format(...args)), 58 | ); 59 | }, 60 | error(...args) { 61 | console.log( 62 | chalk.bold.bgRgb(247, 38, 33)("ERROR "), 63 | chalk.rgb(255, 38, 0)(util.format(...args)), 64 | ); 65 | }, 66 | warn(...args) { 67 | console.log( 68 | chalk.bold.bgRgb(255, 153, 0)("WARNING "), 69 | chalk.redBright(util.format(...args)), 70 | ); 71 | }, 72 | trace(...args) { 73 | console.log( 74 | chalk.grey("TRACE "), 75 | chalk.white(util.format(...args)), 76 | ); 77 | }, 78 | debug(...args) { 79 | console.log( 80 | chalk.bold.bgRgb(66, 167, 245)("DEBUG "), 81 | chalk.white(util.format(...args)), 82 | ); 83 | }, 84 | }; 85 | }, 86 | enumerable: true, 87 | }, 88 | 89 | getContentType: { 90 | value(content) { 91 | if (content) { 92 | const keys = Object.keys(content); 93 | const key = keys.find( 94 | (k) => 95 | (k === "conversation" || 96 | k.endsWith("Message") || 97 | k.endsWith("V2") || 98 | k.endsWith("V3")) && 99 | k !== "senderKeyDistributionMessage", 100 | ); 101 | return key; 102 | } 103 | }, 104 | enumerable: true, 105 | }, 106 | 107 | decodeJid: { 108 | value(jid) { 109 | if (/:\d+@/gi.test(jid)) { 110 | const decode = baileys.jidNormalizedUser(jid); 111 | return decode; 112 | } else return jid; 113 | }, 114 | }, 115 | 116 | generateMessageID: { 117 | value(id = "3EB0", length = 18) { 118 | return id + Crypto.randomBytes(length).toString("hex").toUpperCase(); 119 | }, 120 | }, 121 | 122 | getName: { 123 | value(jid) { 124 | let id = conn.decodeJid(jid), 125 | v; 126 | 127 | if (id?.endsWith("@g.us")) { 128 | return new Promise(async (resolve) => { 129 | v = 130 | conn.contacts[id] || 131 | conn.messages["status@broadcast"]?.array?.find( 132 | (a) => a?.key?.participant === id, 133 | ); 134 | if (!(v.name || v.subject)) v = conn.groupMetadata[id] || {}; 135 | resolve( 136 | v?.name || 137 | v?.subject || 138 | v?.pushName || 139 | parsePhoneNumber("+" + id.replace("@g.us", "")).format( 140 | "INTERNATIONAL", 141 | ), 142 | ); 143 | }); 144 | } else { 145 | v = 146 | id === "0@s.whatsapp.net" 147 | ? { 148 | id, 149 | name: "WhatsApp", 150 | } 151 | : id === conn.decodeJid(conn?.user?.id) 152 | ? conn.user 153 | : conn.contacts[id] || {}; 154 | } 155 | 156 | return ( 157 | v?.name || 158 | v?.subject || 159 | v?.pushName || 160 | v?.verifiedName || 161 | parsePhoneNumber("+" + id.replace("@s.whatsapp.net", "")).format( 162 | "INTERNATIONAL", 163 | ) 164 | ); 165 | }, 166 | }, 167 | 168 | sendContact: { 169 | async value(jid, number, quoted, options = {}) { 170 | let list = []; 171 | 172 | for (let v of number) { 173 | list.push({ 174 | displayName: await conn.getName(v), 175 | vcard: `BEGIN:VCARD\nVERSION:3.0\nN:${await conn.getName( 176 | v + "@s.whatsapp.net", 177 | )}\nFN:${await conn.getName( 178 | v + "@s.whatsapp.net", 179 | )}\nitem1.TEL;waid=${v}:${v}\nitem1.X-ABLabel:Ponsel\nitem2.EMAIL;type=INTERNET:alisaadev@gmail.com\nitem2.X-ABLabel:Email\nitem3.URL:https://nhentai.net\nitem3.X-ABLabel:Instagram\nitem4.ADR:;;Indonesia;;;;\nitem4.X-ABLabel:Region\nEND:VCARD`, 180 | }); 181 | } 182 | 183 | return conn.sendMessage( 184 | jid, 185 | { 186 | contacts: { 187 | displayName: `${list.length} Contact`, 188 | contacts: list, 189 | }, 190 | mentions: quoted?.participant 191 | ? [conn.decodeJid(quoted?.participant)] 192 | : [conn.decodeJid(conn.user?.id)], 193 | ...options, 194 | }, 195 | { quoted, ...options }, 196 | ); 197 | }, 198 | enumerable: true, 199 | }, 200 | 201 | parseMention: { 202 | value(text) { 203 | return ( 204 | [...text.matchAll(/@([0-9]{5,16}|0)/g)].map( 205 | (v) => v[1] + "@s.whatsapp.net", 206 | ) || [] 207 | ); 208 | }, 209 | }, 210 | 211 | downloadMediaMessage: { 212 | async value(message, filename) { 213 | let mime = { 214 | imageMessage: "image", 215 | videoMessage: "video", 216 | stickerMessage: "sticker", 217 | documentMessage: "document", 218 | audioMessage: "audio", 219 | ptvMessage: "video", 220 | }[message.type]; 221 | 222 | if ("thumbnailDirectPath" in message.msg && !("url" in message.msg)) { 223 | message = { 224 | directPath: message.msg.thumbnailDirectPath, 225 | mediaKey: message.msg.mediaKey, 226 | }; 227 | mime = "thumbnail-link"; 228 | } else { 229 | message = message.msg; 230 | } 231 | 232 | return await baileys.toBuffer( 233 | await baileys.downloadContentFromMessage(message, mime), 234 | ); 235 | }, 236 | enumerable: true, 237 | }, 238 | 239 | sendMedia: { 240 | async value(jid, url, quoted = "", options = {}) { 241 | let { mime, data: buffer, ext, size } = await Function.getFile(url); 242 | mime = options?.mimetype ? options.mimetype : mime; 243 | let data = { text: "" }, 244 | mimetype = /audio/i.test(mime) ? "audio/mpeg" : mime; 245 | 246 | if (size > 45000000) 247 | data = { 248 | document: buffer, 249 | mimetype: mime, 250 | fileName: options?.fileName 251 | ? options.fileName 252 | : `${conn.user?.name} (${new Date()}).${ext}`, 253 | ...options, 254 | }; 255 | else if (options.asDocument) 256 | data = { 257 | document: buffer, 258 | mimetype: mime, 259 | fileName: options?.fileName 260 | ? options.fileName 261 | : `${conn.user?.name} (${new Date()}).${ext}`, 262 | ...options, 263 | }; 264 | else if (options.asSticker || /webp/.test(mime)) { 265 | let pathFile = await writeExif( 266 | { mimetype, data: buffer }, 267 | { ...options }, 268 | ); 269 | data = { 270 | sticker: fs.readFileSync(pathFile), 271 | mimetype: "image/webp", 272 | ...options, 273 | }; 274 | fs.existsSync(pathFile) ? await fs.promises.unlink(pathFile) : ""; 275 | } else if (/image/.test(mime)) 276 | data = { 277 | image: buffer, 278 | mimetype: options?.mimetype ? options.mimetype : "image/png", 279 | ...options, 280 | }; 281 | else if (/video/.test(mime)) 282 | data = { 283 | video: buffer, 284 | mimetype: options?.mimetype ? options.mimetype : "video/mp4", 285 | ...options, 286 | }; 287 | else if (/audio/.test(mime)) 288 | data = { 289 | audio: buffer, 290 | mimetype: options?.mimetype ? options.mimetype : "audio/mpeg", 291 | ...options, 292 | }; 293 | else 294 | data = { 295 | document: buffer, 296 | mimetype: mime, 297 | ...options, 298 | }; 299 | 300 | return await conn.sendMessage(jid, data, { 301 | quoted, 302 | ...options, 303 | }); 304 | }, 305 | enumerable: true, 306 | }, 307 | 308 | cMod: { 309 | value(jid, copy, text = "", sender = conn.user.id, options = {}) { 310 | let mtype = conn.getContentType(copy.message); 311 | let content = copy.message[mtype]; 312 | 313 | if (typeof content === "string") copy.message[mtype] = text || content; 314 | else if (content.caption) content.caption = text || content.text; 315 | else if (content.text) content.text = text || content.text; 316 | if (typeof content !== "string") { 317 | copy.message[mtype] = { ...content, ...options }; 318 | copy.message[mtype].contextInfo = { 319 | ...(content.contextInfo || {}), 320 | mentionedJid: 321 | options.mentions || content.contextInfo?.mentionedJid || [], 322 | }; 323 | } 324 | 325 | if (copy.key.participant) 326 | sender = copy.key.participant = sender || copy.key.participant; 327 | if (copy.key.remoteJid.includes("@s.whatsapp.net")) 328 | sender = sender || copy.key.remoteJid; 329 | else if (copy.key.remoteJid.includes("@broadcast")) 330 | sender = sender || copy.key.remoteJid; 331 | copy.key.remoteJid = jid; 332 | copy.key.fromMe = baileys.areJidsSameUser(sender, conn.user.id); 333 | return baileys.proto.WebMessageInfo.fromObject(copy); 334 | }, 335 | }, 336 | 337 | sendPoll: { 338 | async value(chatId, name, values, options = {}) { 339 | let selectableCount = options?.selectableCount 340 | ? options.selectableCount 341 | : 1; 342 | 343 | return await conn.sendMessage( 344 | chatId, 345 | { 346 | poll: { 347 | name, 348 | values, 349 | selectableCount, 350 | }, 351 | ...options, 352 | }, 353 | { ...options }, 354 | ); 355 | }, 356 | enumerable: true, 357 | }, 358 | 359 | setProfilePicture: { 360 | async value(jid, media, type = "full") { 361 | let { data } = await Function.getFile(media); 362 | 363 | if (/full/i.test(type)) { 364 | data = await Function.resizeImage(media, 720); 365 | await conn.query({ 366 | tag: "iq", 367 | attrs: { 368 | to: await conn.decodeJid(jid), 369 | type: "set", 370 | xmlns: "w:profile:picture", 371 | }, 372 | content: [ 373 | { 374 | tag: "picture", 375 | attrs: { 376 | type: "image", 377 | }, 378 | content: data, 379 | }, 380 | ], 381 | }); 382 | } else { 383 | data = await Function.resizeImage(media, 640); 384 | await conn.query({ 385 | tag: "iq", 386 | attrs: { 387 | to: await conn.decodeJid(jid), 388 | type: "set", 389 | xmlns: "w:profile:picture", 390 | }, 391 | content: [ 392 | { 393 | tag: "picture", 394 | attrs: { 395 | type: "image", 396 | }, 397 | content: data, 398 | }, 399 | ], 400 | }); 401 | } 402 | }, 403 | enumerable: true, 404 | }, 405 | 406 | sendGroupV4Invite: { 407 | async value( 408 | jid, 409 | groupJid, 410 | inviteCode, 411 | inviteExpiration, 412 | groupName, 413 | jpegThumbnail, 414 | caption = "Invitation to join my WhatsApp Group", 415 | options = {}, 416 | ) { 417 | const media = await baileys.prepareWAMessageMedia( 418 | { 419 | image: (await Function.getFile(jpegThumbnail)).data, 420 | }, 421 | { 422 | upload: conn.waUploadToServer, 423 | }, 424 | ); 425 | 426 | const message = baileys.proto.Message.fromObject({ 427 | groupJid, 428 | inviteCode, 429 | inviteExpiration: inviteExpiration 430 | ? parseInt(inviteExpiration) 431 | : +new Date(new Date() + 3 * 86400000), 432 | groupName, 433 | jpegThumbnail: media.imageMessage?.jpegThumbnail || jpegThumbnail, 434 | caption, 435 | }); 436 | 437 | const m = baileys.generateWAMessageFromContent(jid, message, { 438 | userJid: conn.user?.id, 439 | }); 440 | 441 | await conn.relayMessage(jid, m.message, { 442 | messageId: m.key.id, 443 | }); 444 | 445 | return m; 446 | }, 447 | enumerable: true, 448 | }, 449 | 450 | sendListM: { 451 | async value(jid, text, footer, list, url, quoted, options = {}) { 452 | let header = { 453 | hasMediaAttachment: false, 454 | }; 455 | 456 | let { mime, data: buffer, ext, size } = await Function.getFile(url); 457 | 458 | if (/image|video/i.test(mime)) { 459 | let media; 460 | if (/image/i.test(mime)) { 461 | media = await prepareWAMessageMedia( 462 | { image: buffer }, 463 | { upload: conn.waUploadToServer }, 464 | ); 465 | } else if (/video/i.test(mime)) { 466 | media = await prepareWAMessageMedia( 467 | { video: buffer }, 468 | { upload: conn.waUploadToServer }, 469 | ); 470 | } 471 | 472 | header = { 473 | hasMediaAttachment: true, 474 | ...media, 475 | }; 476 | } 477 | 478 | let msg = generateWAMessageFromContent( 479 | jid, 480 | { 481 | viewOnceMessage: { 482 | message: { 483 | messageContextInfo: { 484 | deviceListMetadata: {}, 485 | deviceListMetadataVersion: 2, 486 | }, 487 | interactiveMessage: proto.Message.InteractiveMessage.create({ 488 | body: proto.Message.InteractiveMessage.Body.create({ 489 | text: text, 490 | }), 491 | footer: proto.Message.InteractiveMessage.Footer.create({ 492 | text: footer, 493 | }), 494 | header: 495 | proto.Message.InteractiveMessage.Header.create(header), 496 | nativeFlowMessage: 497 | proto.Message.InteractiveMessage.NativeFlowMessage.create({ 498 | buttons: [ 499 | { 500 | name: "single_select", 501 | buttonParamsJson: JSON.stringify({ 502 | title: "Click Here", 503 | sections: list, 504 | }), 505 | }, 506 | ], 507 | }), 508 | contextInfo: options.contextInfo || {}, 509 | }), 510 | }, 511 | }, 512 | }, 513 | { quoted, userJid: quoted.key.remoteJid }, 514 | ); 515 | 516 | conn.relayMessage(jid, msg.message, { 517 | messageId: msg.key.id, 518 | }); 519 | }, 520 | enumerable: true, 521 | writable: true, 522 | }, 523 | sendQuick: { 524 | async value( 525 | jid, 526 | message, 527 | footer, 528 | media = null, 529 | buttons, 530 | quoted, 531 | options = {}, 532 | ) { 533 | let header = { 534 | hasMediaAttachment: false, 535 | }; 536 | 537 | let { mime, data: buffer, ext, size } = await Function.getFile(media); 538 | 539 | if (/image|video/i.test(mime)) { 540 | let media; 541 | if (/image/i.test(mime)) { 542 | media = await prepareWAMessageMedia( 543 | { image: buffer }, 544 | { upload: conn.waUploadToServer }, 545 | ); 546 | } else if (/video/i.test(mime)) { 547 | media = await prepareWAMessageMedia( 548 | { video: buffer }, 549 | { upload: conn.waUploadToServer }, 550 | ); 551 | } 552 | 553 | header = { 554 | hasMediaAttachment: true, 555 | ...media, 556 | }; 557 | } 558 | 559 | let buttonsArray = buttons.map(([buttonText, quickText]) => ({ 560 | name: "quick_reply", 561 | buttonParamsJson: JSON.stringify({ 562 | display_text: buttonText, 563 | id: quickText, 564 | }), 565 | })); 566 | let content = { 567 | viewOnceMessage: { 568 | message: { 569 | messageContextInfo: { 570 | deviceListMetadata: {}, 571 | deviceListMetadataVersion: 2, 572 | }, 573 | interactiveMessage: proto.Message.InteractiveMessage.create({ 574 | body: proto.Message.InteractiveMessage.Body.create({ 575 | text: message, 576 | }), 577 | footer: proto.Message.InteractiveMessage.Footer.create({ 578 | text: footer, 579 | }), 580 | header: proto.Message.InteractiveMessage.Header.create(header), 581 | nativeFlowMessage: 582 | proto.Message.InteractiveMessage.NativeFlowMessage.create({ 583 | buttons: buttonsArray, 584 | }), 585 | contextInfo: options.contextInfo || {}, 586 | }), 587 | }, 588 | }, 589 | }; 590 | let msg = generateWAMessageFromContent( 591 | jid, 592 | content, 593 | { quoted: quoted, ephemeralExpiration: WA_DEFAULT_EPHEMERAL }, 594 | { quoted, userJid: quoted.key.remoteJid }, 595 | ); 596 | await conn.relayMessage(jid, msg.message, { 597 | messageId: msg.key.id, 598 | }); 599 | }, 600 | enumerable: true, 601 | writable: true, 602 | }, 603 | }); 604 | 605 | if (conn.user?.id) conn.user.jid = conn.decodeJid(conn.user?.id); 606 | return conn; 607 | } 608 | 609 | export async function Serialize(conn, msg) { 610 | const m = {}; 611 | const botNumber = conn.decodeJid(conn.user?.id); 612 | 613 | if (!msg.message) return; 614 | if (msg.key && msg.key.remoteJid == "status@broadcast") return; 615 | 616 | m.message = baileys.extractMessageContent(msg.message); 617 | 618 | if (msg.key) { 619 | m.key = msg.key; 620 | m.chat = m.key.remoteJid.startsWith("status") 621 | ? jidNormalizedUser(m.key.participant) 622 | : jidNormalizedUser(m.key.remoteJid); 623 | m.fromMe = m.key.fromMe; 624 | m.id = m.key.id; 625 | m.isBaileys = 626 | (m.id?.startsWith("3EB0") && m.id?.length === 22) || 627 | m.id?.length === 16 || 628 | false; 629 | m.isGroup = m.chat.endsWith("@g.us"); 630 | m.participant = !m.isGroup ? false : m.key.participant; 631 | m.sender = conn.decodeJid( 632 | m.fromMe ? conn.user.id : m.isGroup ? m.participant : m.chat, 633 | ); 634 | } 635 | 636 | m.pushName = msg.pushName; 637 | m.isOwner = 638 | m.sender && 639 | [...global.owner, botNumber.split("@")[0]].includes( 640 | m.sender.replace(/\D+/g, ""), 641 | ); 642 | 643 | if (m.isGroup) { 644 | m.metadata = await conn.groupMetadata(m.chat); 645 | m.admins = m.metadata.participants.reduce( 646 | (memberAdmin, memberNow) => 647 | (memberNow.admin 648 | ? memberAdmin.push({ id: memberNow.id, admin: memberNow.admin }) 649 | : [...memberAdmin]) && memberAdmin, 650 | [], 651 | ); 652 | m.isAdmin = !!m.admins.find((member) => member.id === m.sender); 653 | m.isBotAdmin = !!m.admins.find((member) => member.id === botNumber); 654 | } 655 | 656 | if (m.message) { 657 | m.type = conn.getContentType(m.message) || Object.keys(m.message)[0]; 658 | m.msg = 659 | baileys.extractMessageContent(m.message[m.type]) || m.message[m.type]; 660 | m.mentions = m.msg?.contextInfo?.mentionedJid || []; 661 | m.body = 662 | m.msg?.text || 663 | m.msg?.conversation || 664 | m.msg?.caption || 665 | m.message?.conversation || 666 | m.msg?.selectedButtonId || 667 | m.msg?.singleSelectReply?.selectedRowId || 668 | m.msg?.selectedId || 669 | m.msg?.contentText || 670 | m.msg?.selectedDisplayText || 671 | m.msg?.title || 672 | m.msg?.name || 673 | ""; 674 | // respon btn 675 | if (m.type === "interactiveResponseMessage") { 676 | let msg = m.message[m.type] || m.msg; 677 | if (msg.nativeFlowResponseMessage && !m.isBot) { 678 | let { id } = JSON.parse(msg.nativeFlowResponseMessage.paramsJson) || {}; 679 | if (id) { 680 | let emit_msg = { 681 | key: { 682 | ...m.key, 683 | }, 684 | message: { 685 | extendedTextMessage: { 686 | text: id, 687 | }, 688 | }, 689 | pushName: m.pushName, 690 | messageTimestamp: m.messageTimestamp || 754785898978, 691 | }; 692 | return conn.ev.emit("messages.upsert", { 693 | messages: [emit_msg], 694 | type: "notify", 695 | }); 696 | } 697 | } 698 | } 699 | m.prefix = global.prefix.test(m.body) 700 | ? m.body.match(global.prefix)[0] 701 | : "."; 702 | m.command = 703 | m.body && m.body.replace(m.prefix, "").trim().split(/ +/).shift(); 704 | m.arg = 705 | m.body 706 | .trim() 707 | .split(/ +/) 708 | .filter((a) => a) || []; 709 | m.args = 710 | m.body 711 | .trim() 712 | .replace(new RegExp("^" + Function.escapeRegExp(m.prefix), "i"), "") 713 | .replace(m.command, "") 714 | .split(/ +/) 715 | .filter((a) => a) || []; 716 | m.text = m.args.join(" "); 717 | m.expiration = m.msg?.contextInfo?.expiration || 0; 718 | m.timestamp = 719 | (typeof msg.messageTimestamp === "number" 720 | ? msg.messageTimestamp 721 | : msg.messageTimestamp.low 722 | ? msg.messageTimestamp.low 723 | : msg.messageTimestamp.high) || m.msg.timestampMs * 1000; 724 | m.isMedia = !!m.msg?.mimetype || !!m.msg?.thumbnailDirectPath; 725 | 726 | if (m.isMedia) { 727 | m.mime = m.msg?.mimetype; 728 | m.size = m.msg?.fileLength; 729 | m.height = m.msg?.height || ""; 730 | m.width = m.msg?.width || ""; 731 | 732 | if (/webp/i.test(m.mime)) { 733 | m.isAnimated = m.msg?.isAnimated; 734 | } 735 | } 736 | 737 | m.reply = async (text, options = {}) => { 738 | let chatId = options?.from ? options.from : m.chat; 739 | let quoted = options?.quoted ? options.quoted : m; 740 | 741 | if ( 742 | Buffer.isBuffer(text) || 743 | /^data:.?\/.*?;base64,/i.test(text) || 744 | /^https?:\/\//.test(text) || 745 | fs.existsSync(text) 746 | ) { 747 | let data = await Function.getFile(text); 748 | 749 | if ( 750 | !options.mimetype && 751 | (/utf-8|json/i.test(data.mime) || data.ext == ".bin" || !data.ext) 752 | ) { 753 | return conn.sendMessage( 754 | chatId, 755 | { 756 | text, 757 | mentions: [m.sender, ...conn.parseMention(text)], 758 | ...options, 759 | }, 760 | { quoted, ephemeralExpiration: m.expiration, ...options }, 761 | ); 762 | } else { 763 | return conn.sendMedia(m.chat, data.data, quoted, { 764 | ephemeralExpiration: m.expiration, 765 | ...options, 766 | }); 767 | } 768 | } else { 769 | if (!!global.msg[text]) text = global.msg[text]; 770 | return conn.sendMessage( 771 | chatId, 772 | { 773 | text, 774 | mentions: [m.sender, ...conn.parseMention(text)], 775 | ...options, 776 | }, 777 | { quoted, ephemeralExpiration: m.expiration, ...options }, 778 | ); 779 | } 780 | }; 781 | 782 | m.download = (filepath) => { 783 | if (filepath) return conn.downloadMediaMessage(m, filepath); 784 | else return conn.downloadMediaMessage(m); 785 | }; 786 | } 787 | 788 | // quoted line 789 | m.isQuoted = false; 790 | 791 | if (m.msg?.contextInfo?.quotedMessage) { 792 | m.isQuoted = true; 793 | m.quoted = {}; 794 | m.quoted.message = baileys.extractMessageContent( 795 | m.msg?.contextInfo?.quotedMessage, 796 | ); 797 | 798 | if (m.quoted.message) { 799 | m.quoted.type = 800 | conn.getContentType(m.quoted.message) || 801 | Object.keys(m.quoted.message)[0]; 802 | m.quoted.msg = 803 | baileys.extractMessageContent(m.quoted.message[m.quoted.type]) || 804 | m.quoted.message[m.quoted.type]; 805 | m.quoted.key = { 806 | remoteJid: m.msg?.contextInfo?.remoteJid || m.chat, 807 | participant: m.msg?.contextInfo?.remoteJid?.endsWith("g.us") 808 | ? conn.decodeJid(m.msg?.contextInfo?.participant) 809 | : false, 810 | fromMe: baileys.areJidsSameUser( 811 | conn.decodeJid(m.msg?.contextInfo?.participant), 812 | conn.decodeJid(conn.user?.id), 813 | ), 814 | id: m.msg?.contextInfo?.stanzaId, 815 | }; 816 | 817 | m.quoted.from = m.quoted.key.remoteJid; 818 | m.quoted.fromMe = m.quoted.key.fromMe; 819 | m.quoted.id = m.msg?.contextInfo?.stanzaId; 820 | m.quoted.isBaileys = 821 | (m.quoted?.id?.startsWith("3EB0") && m.quoted?.id?.length === 22) || 822 | m.quoted?.id?.length === 16 || 823 | false; 824 | m.quoted.isGroup = m.quoted.from.endsWith("@g.us"); 825 | m.quoted.participant = m.quoted.key.participant; 826 | m.quoted.sender = conn.decodeJid(m.msg?.contextInfo?.participant); 827 | m.quoted.isOwner = 828 | m.quoted.sender && 829 | [...global.owner, botNumber.split("@")[0]].includes( 830 | m.quoted.sender.replace(/\D+/g, ""), 831 | ); 832 | 833 | if (m.quoted.isGroup) { 834 | m.quoted.metadata = await conn.groupMetadata(m.quoted.from); 835 | m.quoted.admins = m.quoted.metadata.participants.reduce( 836 | (memberAdmin, memberNow) => 837 | (memberNow.admin 838 | ? memberAdmin.push({ id: memberNow.id, admin: memberNow.admin }) 839 | : [...memberAdmin]) && memberAdmin, 840 | [], 841 | ); 842 | m.quoted.isAdmin = !!m.quoted.admins.find( 843 | (member) => member.id === m.quoted.sender, 844 | ); 845 | m.quoted.isBotAdmin = !!m.quoted.admins.find( 846 | (member) => member.id === botNumber, 847 | ); 848 | } 849 | 850 | m.quoted.mentions = m.quoted.msg?.contextInfo?.mentionedJid || []; 851 | m.quoted.body = 852 | m.quoted.msg?.text || 853 | m.quoted.msg?.caption || 854 | m.quoted?.message?.conversation || 855 | m.quoted.msg?.selectedButtonId || 856 | m.quoted.msg?.singleSelectReply?.selectedRowId || 857 | m.quoted.msg?.selectedId || 858 | m.quoted.msg?.contentText || 859 | m.quoted.msg?.selectedDisplayText || 860 | m.quoted.msg?.title || 861 | m.quoted?.msg?.name || 862 | ""; 863 | m.quoted.prefix = global.prefix.test(m.quoted.body) 864 | ? m.quoted.body.match(global.prefix)[0] 865 | : "."; 866 | m.quoted.command = 867 | m.quoted.body && 868 | m.quoted.body.replace(m.quoted.prefix, "").trim().split(/ +/).shift(); 869 | m.quoted.arg = 870 | m.quoted.body 871 | .trim() 872 | .split(/ +/) 873 | .filter((a) => a) || []; 874 | m.quoted.args = 875 | m.quoted.body 876 | .trim() 877 | .replace( 878 | new RegExp("^" + Function.escapeRegExp(m.quoted.prefix), "i"), 879 | "", 880 | ) 881 | .replace(m.quoted.command, "") 882 | .split(/ +/) 883 | .filter((a) => a) || []; 884 | m.quoted.text = m.quoted.args.join(" "); 885 | m.quoted.isMedia = 886 | !!m.quoted.msg?.mimetype || !!m.quoted.msg?.thumbnailDirectPath; 887 | 888 | if (m.quoted.isMedia) { 889 | m.quoted.mime = m.quoted.msg?.mimetype; 890 | m.quoted.size = m.quoted.msg?.fileLength; 891 | m.quoted.height = m.quoted.msg?.height || ""; 892 | m.quoted.width = m.quoted.msg?.width || ""; 893 | if (/webp/i.test(m.quoted.mime)) { 894 | m.quoted.isAnimated = m?.quoted?.msg?.isAnimated || false; 895 | } 896 | } 897 | 898 | m.quoted.reply = (text, options = {}) => { 899 | return m.reply(text, { quoted: m.quoted, ...options }); 900 | }; 901 | 902 | m.quoted.download = (filepath) => { 903 | if (filepath) return conn.downloadMediaMessage(m.quoted, filepath); 904 | else return conn.downloadMediaMessage(m.quoted); 905 | }; 906 | } 907 | } 908 | 909 | return m; 910 | } 911 | 912 | export function protoType() { 913 | Buffer.prototype.toArrayBuffer = function toArrayBufferV2() { 914 | const ab = new ArrayBuffer(this.length); 915 | const view = new Uint8Array(ab); 916 | for (let i = 0; i < this.length; ++i) { 917 | view[i] = this[i]; 918 | } 919 | return ab; 920 | }; 921 | Buffer.prototype.toArrayBufferV2 = function toArrayBuffer() { 922 | return this.buffer.slice( 923 | this.byteOffset, 924 | this.byteOffset + this.byteLength, 925 | ); 926 | }; 927 | ArrayBuffer.prototype.toBuffer = function toBuffer() { 928 | return Buffer.from(new Uint8Array(this)); 929 | }; 930 | Uint8Array.prototype.getFileType = 931 | ArrayBuffer.prototype.getFileType = 932 | Buffer.prototype.getFileType = 933 | async function getFileType() { 934 | return await fileTypeFromBuffer(this); 935 | }; 936 | String.prototype.isNumber = Number.prototype.isNumber = isNumber; 937 | String.prototype.capitalize = function capitalize() { 938 | return this.charAt(0).toUpperCase() + this.slice(1, this.length); 939 | }; 940 | String.prototype.capitalizeV2 = function capitalizeV2() { 941 | const str = this.split(" "); 942 | return str.map((v) => v.capitalize()).join(" "); 943 | }; 944 | String.prototype.decodeJid = function decodeJid() { 945 | if (/:\d+@/gi.test(this)) { 946 | const decode = baileys.jidDecode(this) || {}; 947 | return ( 948 | (decode.user && decode.server && decode.user + "@" + decode.server) || 949 | this 950 | ).trim(); 951 | } else return this.trim(); 952 | }; 953 | Number.prototype.toTimeString = function toTimeString() { 954 | const seconds = Math.floor((this / 1000) % 60); 955 | const minutes = Math.floor((this / (60 * 1000)) % 60); 956 | const hours = Math.floor((this / (60 * 60 * 1000)) % 24); 957 | const days = Math.floor(this / (24 * 60 * 60 * 1000)); 958 | return ( 959 | (days ? `${days} day(s) ` : "") + 960 | (hours ? `${hours} hour(s) ` : "") + 961 | (minutes ? `${minutes} minute(s) ` : "") + 962 | (seconds ? `${seconds} second(s)` : "") 963 | ).trim(); 964 | }; 965 | Number.prototype.getRandom = 966 | String.prototype.getRandom = 967 | Array.prototype.getRandom = 968 | getRandom; 969 | } 970 | 971 | function isNumber() { 972 | const int = parseInt(this); 973 | return typeof int === "number" && !isNaN(int); 974 | } 975 | 976 | function getRandom() { 977 | if (Array.isArray(this) || this instanceof String) 978 | return this[Math.floor(Math.random() * this.length)]; 979 | return Math.floor(Math.random() * this); 980 | } 981 | --------------------------------------------------------------------------------