├── ryzumi.webp ├── src └── avatar_contact.png ├── ASSETS_LICENSE.txt ├── plugins ├── owner-unbanchat.js ├── group-link.js ├── group-tagme.js ├── _expired.js ├── main-afk.js ├── owner-leavegc.js ├── main-ceksn.js ├── _premium.js ├── tool-qrcode.js ├── owner-banchat.js ├── owner-getdb.js ├── tool-readmore.js ├── tool-ci.js ├── owner-restart.js ├── owner-sesi.js ├── owner-tagall.js ├── group-setnamegc.js ├── group-revoke.js ├── owner-setbotpp.js ├── cmd-list.js ├── owner-sf.js ├── group-demote.js ├── sticker-getexif.js ├── cmd-lock.js ├── main-unregister.js ├── group-setppgc.js ├── group-promote.js ├── cmd-del.js ├── owner-sp.js ├── owner-exec2.js ├── group-delete.js ├── owner-blocklist.js ├── sticker-wm.js ├── _autoban.js.ba ├── owner-clearchat.js ├── internet-ppcp.js ├── owner-getfile.js ├── downloader-gitclone.js ├── creator.js ├── group-settings.js ├── donasi.js ├── youtube-yts.js ├── image-iqc.js ├── sticker-brat.js ├── tool-ip.js ├── tool-carbon.js ├── info-totalfitur.js ├── tool-readviewonce.js ├── owner-banuser.js ├── owner-unbanuser.js ├── group-tagall.js ├── tool-translate.js ├── owner-df.js ├── main-claimlimit.js ├── sticker-meme.js ├── ai-animediff.js ├── cmd-set.js ├── stalk-instagram.js ├── host-bcgcb.js ├── info-report.js ├── info-gempa.js ├── ai-flux.js ├── ai-colorize.js ├── expired-cek.js ├── owner-gp.js ├── ai-img2txt.js ├── broadcastall.js ├── _cmdWithMedia.js ├── broadcastchats.js ├── sticker-tovideo.js ├── sticker-emojimix.js ├── downloader-danbooru.js ├── ai-deepseek.js ├── _simi.js ├── expired-del.js ├── broadcastgroups.js ├── downloader-soundcloud.js ├── downloader-mediafire.js ├── stalk_tiktok.js ├── ai-toanime.js ├── sticker-qc.js ├── main-register.js ├── image-fakestory.js ├── group-hidetag.js ├── internet-lyrics.js ├── ai-negrosiasi.js ├── info-sholat.js ├── _afk.js ├── anime-info.js ├── ai-faceswap.js ├── group-kick.js ├── owner-cleartmp.js ├── sticker-sticker.js ├── stalk-twitter.js ├── owner-clearsession.js ├── ai-waifu2x.js ├── ai-gemini-image.js ├── image-gimage.js ├── tool-cekpln.js ├── sticker-telegram.js ├── tool-tts.js ├── downloader-slideshare.js ├── internet-ghsearch.js ├── tool-spamwa.js ├── downloader-gdrive.js ├── internet-mahasiswa.js ├── tool-ocr.js ├── tool-chord.js ├── tool-shorturl.js ├── downloader-facebook.js ├── stalk-youtube.js ├── ai-removebg.js ├── downloader-aio.js ├── downloader-threads.js ├── anime-manga.js ├── downloader-krakenfiles.js ├── owner-kick.js ├── tool-uploader.js ├── internet-ssweb.js ├── ai-upscale.js ├── internet-lens.js ├── _memfess-answer.js ├── owner-deluser.js ├── downloader-terabox.js ├── owner-exec.js ├── downloader-mega.js ├── stalk-wa.js ├── levelup.js ├── owner-simulate.js ├── internet-gag.js ├── owner-join.js ├── anime-imagesearch.js ├── sticker-toimg.js ├── stalk-ff.js ├── owner-inspect.js ├── group-info.js ├── group-add.js ├── image-faketweet.js ├── ai-openai.js ├── downloader-twitter.js ├── expired-set.js ├── youtube-yta.js ├── ai-gemini.js ├── tool-cekpajak-bapenda.js ├── downloader-sfile.js ├── youtube-play.js ├── downloader-spotify.js ├── tool-jadwaltv.js ├── youtube-ytv.js ├── memfess.js └── internet-cuaca.js ├── .gitignore ├── lib ├── logs.js ├── levelling.js ├── uploadFile.js ├── uploadImage.js ├── webp2mp4.js └── converter.js ├── test.js ├── package.json └── index.js /ryzumi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShirokamiRyzen/RyzumiMD-ESM/HEAD/ryzumi.webp -------------------------------------------------------------------------------- /src/avatar_contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShirokamiRyzen/RyzumiMD-ESM/HEAD/src/avatar_contact.png -------------------------------------------------------------------------------- /ASSETS_LICENSE.txt: -------------------------------------------------------------------------------- 1 | All visual assets (images, icons, sprites, characters, UI elements) in this repository are © Ryzumi Network. 2 | You may not reuse, redistribute, or modify these assets without explicit permission. 3 | The code remains licensed under GNU GPL v3. 4 | -------------------------------------------------------------------------------- /plugins/owner-unbanchat.js: -------------------------------------------------------------------------------- 1 | let handler = async (m) => { 2 | global.db.data.chats[m.chat].isBanned = false 3 | m.reply('Done!') 4 | } 5 | handler.help = ['unbanchat'] 6 | handler.tags = ['owner'] 7 | handler.command = /^(unbanchat|ubnc)$/i 8 | handler.owner = true 9 | 10 | export default handler -------------------------------------------------------------------------------- /plugins/group-link.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args }) => { 2 | m.reply('https://chat.whatsapp.com/' + await conn.groupInviteCode(m.chat)) 3 | } 4 | handler.help = ['linkgroup'] 5 | handler.tags = ['group'] 6 | handler.command = /^link(gro?up)?$/i 7 | handler.admin = true 8 | handler.group = true 9 | handler.botAdmin = true 10 | 11 | 12 | export default handler -------------------------------------------------------------------------------- /plugins/group-tagme.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | let tag = `@${m.sender.replace(/@.+/, '')}` 3 | let mentionedJid = [m.sender] 4 | conn.reply(m.chat, tag, m, { contextInfo: { mentionedJid }}) 5 | } 6 | handler.help = ['tagme'] 7 | handler.tags = ['group'] 8 | handler.command = /^tagme$/i 9 | 10 | handler.group = false 11 | 12 | export default handler -------------------------------------------------------------------------------- /plugins/_expired.js: -------------------------------------------------------------------------------- 1 | export async function all(m) { 2 | if (!m.isGroup) 3 | return 4 | let chats = global.db.data.chats[m.chat] 5 | if (!chats.expired) 6 | return !0 7 | if (+new Date() > chats.expired) { 8 | await this.reply(m.chat, 'Bye🖐 bot akan left!!') 9 | await this.groupLeave(m.chat) 10 | chats.expired = null 11 | } 12 | } -------------------------------------------------------------------------------- /plugins/main-afk.js: -------------------------------------------------------------------------------- 1 | var handler = async (m, { text }) => { 2 | let user = global.db.data.users[m.sender] 3 | user.afk = + new Date 4 | user.afkReason = text 5 | m.reply('@' + m.sender.split('@')[0] + `is now AFK${text ? ': ' + text : ''} 6 | `) 7 | } 8 | handler.help = ['afk [alasan]'] 9 | handler.tags = ['main'] 10 | handler.command = /^afk$/i 11 | 12 | export default handler 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | sessions 3 | tmp/* 4 | enc/* 5 | *.bak 6 | main.js.bak 7 | plugins_bak/ 8 | handlerr.js 9 | sftp/ 10 | database.json 11 | config.js 12 | bot.sh 13 | test.json 14 | .vscode 15 | *.zip 16 | 17 | #Plugins 18 | plugins/_monitor-mc.js 19 | plugins/_autoviewonce.js 20 | plugins/_RyzumiAPI-IP.js 21 | plugins/_cf_API.js 22 | plugins/ai-farel.js 23 | plugins/tool-reactch.js 24 | -------------------------------------------------------------------------------- /plugins/owner-leavegc.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args, command }) => { 2 | let group = m.chat 3 | await m.reply('Sayonara , , ! 👋😃', m.chat,fkontak) 4 | await conn.groupLeave(group) 5 | } 6 | handler.help = ['leavegc', 'out'] 7 | handler.tags = ['owner'] 8 | handler.command = /^(out|leavegc)$/i 9 | 10 | handler.rowner = true 11 | 12 | export default handler 13 | -------------------------------------------------------------------------------- /plugins/main-ceksn.js: -------------------------------------------------------------------------------- 1 | import { createHash } from 'crypto' 2 | 3 | let Reg = /\|?(.*)([.|] *?)([0-9]*)$/i 4 | let handler = async function (m, { conn, text, usedPrefix }) { 5 | let sn = createHash('md5').update(m.sender).digest('hex') 6 | 7 | m.reply(`*SN:* ${sn}`) 8 | } 9 | 10 | handler.help = ['ceksn'] 11 | handler.tags = ['xp'] 12 | handler.command = /^(ceksn)$/i 13 | handler.register = true 14 | export default handler -------------------------------------------------------------------------------- /plugins/_premium.js: -------------------------------------------------------------------------------- 1 | export async function all(m) { 2 | let user = global.db.data.users[m.sender] 3 | if (m.chat?.endsWith('broadcast')) return; 4 | 5 | if (user?.premiumTime !== 0 && user?.premium) { 6 | if (Date.now() >= user?.premiumTime) { 7 | await m.reply(`Waktu premium Kamu sudah habis!`) 8 | user.premiumTime = 0 9 | user.premium = false 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /plugins/tool-qrcode.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | if (!text) return conn.reply(m.chat, 'Use example: \n.qrcode Shirokami Ryzen', m) 3 | conn.sendFile(m.chat, `https://quickchart.io/qr?size=300&margin=2&text=${encodeURIComponent(text)}`, 'qrcode.png', '¯\\_(ツ)_/¯', m) 4 | } 5 | 6 | handler.help = ['qrcode '] 7 | handler.tags = ['tools'] 8 | handler.command = /^qr(code)?$/i 9 | 10 | export default handler -------------------------------------------------------------------------------- /plugins/owner-banchat.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { participants }) => { 2 | // if (participants.map(v=>v.jid).includes(global.conn.user.jid)) { 3 | global.db.data.chats[m.chat].isBanned = true 4 | m.reply('Done!') 5 | // } else m.reply('Ada nomor host disini...') 6 | } 7 | handler.help = ['banchat'] 8 | handler.tags = ['owner'] 9 | handler.command = /^(banchat|bnc)$/i 10 | 11 | handler.owner = true 12 | 13 | export default handler -------------------------------------------------------------------------------- /plugins/owner-getdb.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | let handler = async (m, { conn, text }) => { 3 | m.reply('Tunggu Sebentar, Sedang mengambil file Database') 4 | let sesi = await fs.readFileSync('./database.json') 5 | return await conn.sendMessage(m.chat, { document: sesi, mimetype: 'application/json', fileName: 'database.json' }, { quoted: m }) 6 | } 7 | handler.help = ['getdb'] 8 | handler.tags = ['owner'] 9 | handler.command = /^(getdb)$/i 10 | 11 | handler.rowner = true 12 | 13 | export default handler -------------------------------------------------------------------------------- /plugins/tool-readmore.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | let [l, r] = text.split`|` 3 | if (!l) l = '' 4 | if (!r) r = '' 5 | conn.reply(m.chat, l + readMore + r, m) 6 | } 7 | handler.help = ['readmore'].map(v => v + ' |') 8 | handler.tags = ['tools'] 9 | handler.command = /^(spoiler|hidetext|readmore|selengkapnya)$/i 10 | 11 | handler.register = true 12 | 13 | export default handler 14 | 15 | const more = String.fromCharCode(8206) 16 | const readMore = more.repeat(4001) -------------------------------------------------------------------------------- /plugins/tool-ci.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn }) => { 2 | if (!m.quoted) throw 'reply saluran channel nya lah' 3 | try { 4 | let id = (await m.getQuotedObj()).msg.contextInfo.forwardedNewsletterMessageInfo 5 | await m.reply(`Name: ${id.newsletterName}\nId: ${id.newsletterJid}`) 6 | } catch (e) { 7 | throw 'Harus chat dari channel bang' 8 | } 9 | } 10 | 11 | handler.help = handler.command = ['ci'] 12 | handler.tags = ['tools'] 13 | 14 | handler.register = true 15 | 16 | export default handler -------------------------------------------------------------------------------- /plugins/owner-restart.js: -------------------------------------------------------------------------------- 1 | import { spawn } from 'child_process' 2 | let handler = async (m, { conn, isROwner, text }) => { 3 | if (!process.send) throw 'Dont: node main.js\nDo: node index.js' 4 | if (global.conn.user.jid == conn.user.jid) { 5 | await m.reply('```R E S T A R T . . .```') 6 | process.send('reset') 7 | } else throw '_eeeeeiiittsssss..._' 8 | } 9 | 10 | handler.help = ['restart'] 11 | handler.tags = ['owner'] 12 | handler.command = /^(res(tart)?)$/i 13 | 14 | handler.rowner = true 15 | 16 | export default handler -------------------------------------------------------------------------------- /plugins/owner-sesi.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | let handler = async (m, { conn, text }) => { 3 | m.reply('Tunggu Sebentar, Sedang mengambil file sesi bot') 4 | let sesi = await fs.readFileSync('./sessions/creds.json') 5 | return await conn.sendMessage(m.chat, { document: sesi, mimetype: 'application/json', fileName: 'creds.json' }, { quoted: m }) 6 | } 7 | handler.help = ['getsessi'] 8 | handler.tags = ['owner'] 9 | handler.command = /^(g(et)?ses?si(on)?(data.json)?)$/i 10 | 11 | handler.rowner = true 12 | 13 | export default handler 14 | -------------------------------------------------------------------------------- /plugins/owner-tagall.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text, participants, isAdmin, isOwner }) => { 2 | let users = participants.map(u => u.id).filter(v => v !== conn.user.jid) 3 | m.reply(`${text ? `${text}\n` : ''}┌─「 Tag All 」\n` + users.map(v => '│◦❒ @' + v.replace(/@.+/, '')).join`\n` + '\n└────', null, { 4 | mentions: users 5 | }) 6 | } 7 | 8 | handler.help = ['o-tagall'] 9 | handler.tags = ['owner'] 10 | handler.command = ['o-tagall'] 11 | handler.owner = true 12 | handler.group = true 13 | 14 | export default handler 15 | -------------------------------------------------------------------------------- /plugins/group-setnamegc.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args, usedPrefix, command }) => { 2 | 3 | await conn.groupUpdateSubject(m.chat, `${args.join(" ")}`); 4 | m.reply('Sukses mengganti nama group') 5 | } 6 | 7 | handler.help = ['setgcname'] 8 | handler.tags = ['group'] 9 | handler.command = /^setgcname$/i 10 | handler.owner = false 11 | handler.mods = false 12 | handler.premium = false 13 | handler.group = true 14 | handler.private = false 15 | handler.register = false 16 | handler.admin = true 17 | handler.botAdmin = true 18 | 19 | export default handler -------------------------------------------------------------------------------- /plugins/group-revoke.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn }) => { 2 | try { 3 | let rest = await conn.groupRevokeInvite(m.chat); 4 | let linked = 'https://chat.whatsapp.com/' + rest; 5 | 6 | m.reply(linked); 7 | } catch (error) { 8 | console.error(error); 9 | m.reply('Failed to retrieve group invite link'); 10 | } 11 | }; 12 | 13 | handler.help = ['revoke']; 14 | handler.tags = ['group']; 15 | handler.command = /^re(voke|new)(invite|link)?$/i; 16 | handler.group = true; 17 | handler.admin = true; 18 | handler.botAdmin = true; 19 | 20 | export default handler; 21 | -------------------------------------------------------------------------------- /plugins/owner-setbotpp.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args }) => { 2 | let bot = conn.user.jid // Bot 3 | let q = m.quoted ? m.quoted : m 4 | let mime = (q.msg || q).mimetype || '' 5 | if (/image/.test(mime)) { 6 | let img = await q.download() 7 | if (!img) throw `Fotonya Gak Ada Kak *┰ω┰*` 8 | conn.updateProfilePicture(bot, img) 9 | conn.reply(m.chat, 'Selesai Mengganti Profil Bot Kak*>ω<*!', m) 10 | } 11 | } 12 | handler.help = ['setpp'] 13 | handler.tags = ['owner'] 14 | handler.command = /^(setpp)$/i 15 | handler.owner = true 16 | 17 | export default handler -------------------------------------------------------------------------------- /plugins/cmd-list.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn }) => { 2 | conn.reply(m.chat, ` 3 | *DAFTAR CMD* 4 | \`\`\` 5 | ${Object.entries(global.db.data.sticker).map(([key, value], index) => `${index + 1}. ${value.locked ? `(Terkunci) ${key}` : key} : ${value.text}`).join('\n')} 6 | \`\`\` 7 | `.trim(), null, { 8 | mentions: Object.values(global.db.data.sticker).map(x => x.mentionedJid).reduce((a, b) => [...a, ...b], []) 9 | }) 10 | } 11 | 12 | 13 | handler.help = ['listcmd'] 14 | handler.tags = ['database'] 15 | handler.command = ['listcmd'] 16 | 17 | export default handler 18 | -------------------------------------------------------------------------------- /plugins/owner-sf.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | let handler = async (m, { text, usedPrefix, command }) => { 3 | if (!text) throw `uhm.. teksnya mana?\n\npenggunaan:\n${usedPrefix + command} \n\ncontoh:\n${usedPrefix + command} plugins/melcanz.js` 4 | if (!m.quoted.text) throw `balas pesan nya!` 5 | let path = `${text}` 6 | await fs.writeFileSync(path, m.quoted.text) 7 | m.reply(`tersimpan di ${path}`) 8 | } 9 | handler.help = ['sf'].map(v => v + ' ') 10 | handler.tags = ['owner'] 11 | handler.command = /^sf$/i 12 | 13 | handler.rowner = true 14 | export default handler -------------------------------------------------------------------------------- /plugins/group-demote.js: -------------------------------------------------------------------------------- 1 | import { areJidsSameUser } from '@whiskeysockets/baileys' 2 | let handler = async (m, { conn, participants }) => { 3 | let users = m.mentionedJid.filter(u => !areJidsSameUser(u, conn.user.id)) 4 | let user = m.mentionedJid && m.mentionedJid[0] 5 | await conn.groupParticipantsUpdate(m.chat, [user], 'demote') 6 | 7 | m.reply('Succes') 8 | 9 | } 10 | handler.help = ['demote @tag'] 11 | handler.tags = ['group'] 12 | handler.command = /^(demote)$/i 13 | 14 | handler.admin = true 15 | handler.group = true 16 | handler.botAdmin = true 17 | 18 | export default handler -------------------------------------------------------------------------------- /plugins/sticker-getexif.js: -------------------------------------------------------------------------------- 1 | import { format } from 'util' 2 | const { default: { Image } } = await import('node-webpmux') 3 | 4 | let handler = async (m) => { 5 | if (!m.quoted) return m.reply('Tag stikernya!') 6 | if (/sticker/.test(m.quoted.mtype)) { 7 | let img = new Image() 8 | await img.load(await m.quoted.download()) 9 | m.reply(format(JSON.parse(img.exif.slice(22).toString()))) 10 | } 11 | } 12 | handler.help = ['getexif'] 13 | handler.tags = ['maker'] 14 | 15 | handler.command = ['getexif'] 16 | 17 | handler.register = true 18 | 19 | export default handler -------------------------------------------------------------------------------- /plugins/cmd-lock.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text, usedPrefix, command }) => { 2 | if (!m.quoted) throw 'Tag Pesan!' 3 | if (!m.quoted.fileSha256) throw 'SHA256 Hash Missing' 4 | let sticker = db.data.sticker 5 | let hash = Buffer.from(m.quoted.fileSha256).toString('hex') 6 | if (!(hash in sticker)) throw 'Hash not found in database' 7 | sticker[hash].locked = !/^un/i.test(command) 8 | m.reply('Done!') 9 | } 10 | handler.help = ['un', ''].map(v => v + 'lockcmd') 11 | handler.tags = ['database'] 12 | handler.command = /^(un)?lockcmd$/i 13 | 14 | export default handler 15 | -------------------------------------------------------------------------------- /plugins/main-unregister.js: -------------------------------------------------------------------------------- 1 | import { createHash } from 'crypto' 2 | let handler = async function (m, { args }) { 3 | if (!args[0]) throw 'Serial Number kosong' 4 | let user = global.db.data.users[m.sender] 5 | let sn = createHash('md5').update(m.sender).digest('hex') 6 | if (args[0] !== sn) throw 'Serial Number salah' 7 | user.registered = false 8 | m.reply('```Success Unreg !```') 9 | } 10 | handler.help = ['', 'ister'].map(v => 'unreg' + v + ' ') 11 | handler.tags = ['xp'] 12 | 13 | handler.command = /^unreg(ister)?$/i 14 | handler.register = true 15 | 16 | export default handler -------------------------------------------------------------------------------- /plugins/group-setppgc.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, usedPrefix, command }) => { 2 | let q = m.quoted ? m.quoted : m 3 | let mime = (q.msg || q).mimetype || '' 4 | if (/image/.test(mime)) { 5 | let img = await q.download() 6 | if (!img) throw 'Gambar tidak ditemukan' 7 | await conn.updateProfilePicture(m.chat, img) 8 | } else throw `kirim/balas gambar dengan caption *${usedPrefix + command}*` 9 | } 10 | handler.help = ['setppgc'] 11 | handler.tags = ['group'] 12 | 13 | handler.command = /^setppgc$/i 14 | 15 | handler.group = true 16 | handler.admin = true 17 | handler.botAdmin = true 18 | 19 | export default handler -------------------------------------------------------------------------------- /plugins/group-promote.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, participants }) => { 2 | let who = m.quoted ? m.quoted.sender : m.mentionedJid && m.mentionedJid[0] ? m.mentionedJid[0] : text ? (text.replace(/\D/g, '') + '@s.whatsapp.net') : '' 3 | if (!who || who == m.sender) throw 'Reply / tag yang ingin di promote' 4 | conn.groupParticipantsUpdate(m.chat, [who], 'promote') 5 | .then(_ => m.reply('Success')) 6 | 7 | } 8 | handler.help = ['promote @tag'] 9 | handler.tags = ['group'] 10 | handler.command = /^(promote)$/i 11 | handler.admin = true 12 | handler.group = true 13 | handler.botAdmin = true 14 | 15 | export default handler -------------------------------------------------------------------------------- /plugins/cmd-del.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, usedPrefix, text, command }) => { 2 | let hash = text 3 | if (m.quoted && m.quoted.fileSha256) hash = Buffer.from(m.quoted.fileSha256).toString('hex') 4 | if (!hash) throw `Tidak ada hash` 5 | let sticker = global.db.data.sticker 6 | if (sticker[hash] && sticker[hash].locked) throw 'Kamu tidak memiliki izin untuk menghapus perintah stiker ini' 7 | delete sticker[hash] 8 | m.reply(`Berhasil!`) 9 | } 10 | 11 | 12 | handler.help = ['cmd'].map(v => 'del' + v + ' ') 13 | handler.tags = ['database', 'premium'] 14 | handler.command = ['delcmd'] 15 | 16 | export default handler 17 | -------------------------------------------------------------------------------- /plugins/owner-sp.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | 3 | let handler = async (m, { text, usedPrefix, command }) => { 4 | if (!text) throw `uhm.. nama pluginnya mana?\n\ncontoh:\n${usedPrefix + command} test\n(balas pesan berisi kode plugin)` 5 | if (!m.quoted?.text) throw `balas pesan yang berisi kode plugin yang ingin disimpan!` 6 | 7 | let path = `plugins/${text}.js` 8 | await fs.writeFileSync(path, m.quoted.text) 9 | m.reply(`✅ Plugin berhasil disimpan di: ${path}`) 10 | } 11 | 12 | handler.help = ['sp'].map(v => v + ' ') 13 | handler.tags = ['owner'] 14 | handler.command = /^sp$/i 15 | handler.rowner = true 16 | 17 | export default handler 18 | -------------------------------------------------------------------------------- /plugins/owner-exec2.js: -------------------------------------------------------------------------------- 1 | import cp, { exec as _exec } from 'child_process' 2 | import { promisify } from 'util' 3 | let exec = promisify(_exec).bind(cp) 4 | let handler = async (m, { conn, isOwner, command, text }) => { 5 | if (global.conn.user.jid != conn.user.jid) return 6 | m.reply('Executing...') 7 | let o 8 | try { 9 | o = await exec(command.trimStart() + ' ' + text.trimEnd()) 10 | } catch (e) { 11 | o = e 12 | } finally { 13 | let { stdout, stderr } = o 14 | if (stdout.trim()) m.reply(stdout) 15 | if (stderr.trim()) m.reply(stderr) 16 | } 17 | } 18 | handler.customPrefix = /^[$] / 19 | handler.command = new RegExp 20 | handler.owner = true 21 | export default handler 22 | -------------------------------------------------------------------------------- /plugins/group-delete.js: -------------------------------------------------------------------------------- 1 | let handler = function (m) { 2 | let key = {} 3 | try { 4 | key.remoteJid = m.quoted ? m.quoted.fakeObj.key.remoteJid : m.key.remoteJid 5 | key.fromMe = m.quoted ? m.quoted.fakeObj.key.fromMe : m.key.fromMe 6 | key.id = m.quoted ? m.quoted.fakeObj.key.id : m.key.id 7 | key.participant = m.quoted ? m.quoted.fakeObj.participant : m.key.participant 8 | } catch (e) { 9 | console.error(e) 10 | } 11 | conn.sendMessage(m.chat, { delete: key }) 12 | } 13 | handler.help = ['delete'] 14 | handler.tags = ['info'] 15 | handler.command = /^(del|delete|unsend?)$/i 16 | handler.limit = false 17 | handler.admin = true 18 | 19 | export default handler -------------------------------------------------------------------------------- /plugins/owner-blocklist.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn }) => { 2 | await conn.fetchBlocklist().then(async data => { 3 | let txt = `*「 Daftar Nomor Yang Diblokir 」*\n\n*Total:* ${data.length}\n\n┌─\n` 4 | for (let i of data) { 5 | txt += `├ @${i.split("@")[0]}\n` 6 | } 7 | txt += "└────" 8 | return conn.reply(m.chat, txt, m, { mentions: await conn.parseMention(txt) }) 9 | }).catch(err => { 10 | console.log(err); 11 | throw 'tidak ada yang diblokir!' 12 | }) 13 | } 14 | handler.tags = ['info'] 15 | handler.help = ['blocklist'] 16 | handler.command = /^(blocklist)$/i 17 | 18 | handler.owner = true 19 | 20 | export default handler 21 | -------------------------------------------------------------------------------- /plugins/sticker-wm.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | if (!m.quoted) throw 'Quoted the sticker!' 3 | try { 4 | let [packname, ...author] = text.split('|') 5 | author = (author || []).join('|') 6 | let mime = m.quoted.mimetype || '' 7 | if (!/webp/.test(mime)) throw 'Reply sticker!' 8 | let img = await m.quoted.download() 9 | if (!img) throw 'Reply a sticker!' 10 | conn.sendSticker(m.chat, img, m, { packname, author }) 11 | } catch (e) { 12 | console.error(e) 13 | } 14 | } 15 | handler.help = ['wm |'] 16 | handler.tags = ['maker'] 17 | handler.command = /^wm$/i 18 | handler.register = true 19 | handler.premium = true 20 | 21 | export default handler 22 | -------------------------------------------------------------------------------- /lib/logs.js: -------------------------------------------------------------------------------- 1 | const stdouts = []; 2 | const maxLength = 200; 3 | 4 | export let isModified = false; 5 | export default () => { 6 | const oldWrite = process.stdout.write.bind(process.stdout); 7 | const disable = () => { 8 | process.stdout.write = oldWrite; 9 | isModified = false; 10 | }; 11 | process.stdout.write = (chunk, encoding, callback) => { 12 | stdouts.push(Buffer.from(chunk, encoding)); 13 | oldWrite(chunk, encoding, callback); 14 | if (stdouts.length > maxLength) { 15 | stdouts.shift(); 16 | } 17 | }; 18 | isModified = true; 19 | return { disable }; 20 | }; 21 | 22 | export const logs = () => { 23 | return Buffer.concat(stdouts.length > 0 ? stdouts : [Buffer.from('')]); 24 | }; 25 | -------------------------------------------------------------------------------- /plugins/_autoban.js.ba: -------------------------------------------------------------------------------- 1 | let handler = m => m 2 | 3 | handler.before = async function (m) { 4 | let regionData = { 5 | '212': '(+212)', 6 | '265': '(+265)', 7 | '91': '(+91)', 8 | '90': '(+90)', 9 | }; 10 | 11 | for (let countryCode in regionData) { 12 | if (m.sender.startsWith(countryCode)) { 13 | global.db.data.users[m.sender].banned = true 14 | let bannedCountries = Object.values(regionData).join('\n'); 15 | m.reply(`Sorry, you can't use this bot at this time because your country code has been banned due to spam requests.\n\nBlocked List of Countries:\n${bannedCountries}`); 16 | return 17 | } 18 | } 19 | } 20 | 21 | export default handler 22 | -------------------------------------------------------------------------------- /plugins/owner-clearchat.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args }) => { 2 | try { 3 | if (!args[0]) throw 'Input Jid People/Groups' 4 | const jid = args[0] 5 | await conn.chatModify({ 6 | delete: true, 7 | lastMessages: [{ 8 | key: m.key, 9 | messageTimestamp: m.messageTimestamp 10 | }] 11 | }, jid); 12 | conn.reply(m.chat, `Success Cler Chat for ${jid}`, m); 13 | } catch (error) { 14 | console.error(error); 15 | conn.reply(m.chat, 'Terjadi Kesalahan Saat Menghapus Chat, Mohon Perhatikan Jidnya', m); 16 | } 17 | } 18 | handler.help = ['clearchat'] 19 | handler.tags = ['owner'] 20 | handler.owner = true 21 | handler.command = /^(clearchat)$/i 22 | export default handler 23 | -------------------------------------------------------------------------------- /plugins/internet-ppcp.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | let handler = async (m, { conn }) => { 3 | 4 | let data = await (await fetch('https://raw.githubusercontent.com/ShirokamiRyzen/WAbot-DB/main/fitur_db/ppcp.json')).json() 5 | let cita = data[Math.floor(Math.random() * data.length)] 6 | 7 | let cowi = Buffer.from(await (await fetch(cita.cowo)).arrayBuffer()) 8 | await conn.sendFile(m.chat, cowi, '', 'cowok ♂️', m) 9 | let ciwi = Buffer.from(await (await fetch(cita.cewe)).arrayBuffer()) 10 | await conn.sendFile(m.chat, ciwi, '', 'cewek ♀️', m) 11 | } 12 | 13 | handler.help = ['ppcp'] 14 | handler.tags = ['internet'] 15 | handler.command = /^ppcp$/i 16 | handler.limit = false 17 | handler.register = true 18 | 19 | export default handler 20 | -------------------------------------------------------------------------------- /plugins/owner-getfile.js: -------------------------------------------------------------------------------- 1 | import cp from 'child_process' 2 | import { promisify } from 'util' 3 | let exec = promisify(cp.exec).bind(cp) 4 | let handler = async (m, { conn, isROwner, usedPrefix, command, text }) => { 5 | if (!text) throw `uhm.. teksnya mana?\n\ncontoh\n${usedPrefix + command} main` 6 | m.reply('Executing...') 7 | let o 8 | try { 9 | o = await exec('type ' + text) 10 | } catch (e) { 11 | o = e 12 | } finally { 13 | let { stdout, stderr } = o 14 | if (stdout.trim()) m.reply(stdout) 15 | if (stderr.trim()) m.reply(stderr) 16 | } 17 | } 18 | 19 | handler.help = ['getfile'].map(v => v + ' ') 20 | handler.tags = ['owner'] 21 | handler.command = /^(getfile|gf)$/i 22 | 23 | handler.rowner = true 24 | 25 | export default handler -------------------------------------------------------------------------------- /plugins/downloader-gitclone.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | const regex = /(?:https|git)(?::\/\/|@)github\.com[\/:]([^\/:]+)\/(.+)/i 3 | let handler = async (m, {conn, text, args, usedPrefix, command }) => { 4 | if (!args[0]) throw `Example user ${usedPrefix}${command} ShirokamiRyzen/Nao-MD` 5 | let [usr, rep] = text.split`/` 6 | let url = `https://api.github.com/repos/${encodeURIComponent(usr)}/${encodeURIComponent(rep)}/zipball` 7 | let name = `${encodeURIComponent(rep)}.zip` 8 | m.reply(`D o w n l o a d i n g. . .`) 9 | conn.sendFile(m.chat, url, name, null, m) 10 | } 11 | handler.help = ['gitclone /'] 12 | handler.tags = ['downloader'] 13 | handler.command = /gitclone/i 14 | handler.register = true 15 | 16 | handler.limit = false 17 | 18 | export default handler 19 | -------------------------------------------------------------------------------- /plugins/creator.js: -------------------------------------------------------------------------------- 1 | let handler = async (m) => { 2 | const sentMsg = await conn.sendContactArray(m.chat, [ 3 | [`${nomorown}`, `${await conn.getName(nomorown + '@s.whatsapp.net')}`, `💌 Developer Bot `, `Not Famous`, `ryzendesu.vip@gmail.com`, `🇮🇩 Indonesia`, `📍 https://www.ryzumi.vip`, `👤 Owner Nao Bot`], 4 | [`${conn.user.jid.split('@')[0]}`, `${await conn.getName(conn.user.jid)}`, `🎈 Whatsapp Bot`, `📵 Dont Spam`, `ryzumistarlette@gmail.com`, `🇮🇩 Indonesia`, `📍 https://github.com/ShirokamiRyzen/Nao-MD`, `Hanya bot biasa yang kadang error ☺`] 5 | ], fkontak) 6 | await m.reply(`Hello @${m.sender.split(`@`)[0]} Thats my owner, dont spam or i will block u`) 7 | } 8 | 9 | handler.help = ['owner', 'creator'] 10 | handler.tags = ['main', 'info'] 11 | handler.command = /^(owner|creator)/i 12 | export default handler -------------------------------------------------------------------------------- /plugins/group-settings.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args, usedPrefix, command }) => { 2 | let isClose = { // Switch Case Like :v 3 | 'open': 'not_announcement', 4 | 'close': 'announcement', 5 | 'unlock': 'unlocked', 6 | 'lock': 'locked', 7 | }[(args[0] || '')] 8 | if (isClose === undefined) 9 | throw ` 10 | *Format salah! Contoh :* 11 | *○ ${usedPrefix + command} close* 12 | *○ ${usedPrefix + command} open* 13 | *○ ${usedPrefix + command} unlock* 14 | *○ ${usedPrefix + command} lock* 15 | `.trim() 16 | await conn.groupSettingUpdate(m.chat, isClose) 17 | } 18 | handler.help = ['group *open / close*'] 19 | handler.tags = ['group'] 20 | handler.command = /^(group)$/i 21 | 22 | handler.admin = true 23 | handler.botAdmin = true 24 | 25 | export default handler 26 | -------------------------------------------------------------------------------- /plugins/donasi.js: -------------------------------------------------------------------------------- 1 | let handler = async (m) => { 2 | let gambar = 'https://api.ryzumi.vip/images/qris.png' 3 | //let saweria = global.psaweria 4 | let qris = global.qris 5 | let numberowner = global.nomorown 6 | let anu = `Hai 👋 7 | Kalian bisa membeli paket premium melalui: 8 | ┌〔 Premium • Emoney 〕 9 | ├ QRIS : ${qris} 10 | └──── 11 | List Premium: 12 | 10k = Premium 20 Hari 13 | 20k = Premium 40 Hari 14 | 25k = Premium 60 Hari 15 | 50k = Premium 180 Hari 16 | 17 | Terimakasih :D 18 | 19 | Contact Owner: 20 | wa.me/${numberowner} (Owner) 21 | ` 22 | let qris_img = Buffer.from(await (await fetch(gambar)).arrayBuffer()) 23 | await conn.sendFile(m.chat, qris_img, '', anu, m) 24 | } 25 | 26 | handler.help = ['premium'] 27 | handler.tags = ['main'] 28 | handler.command = /^(premium)$/i 29 | 30 | export default handler 31 | -------------------------------------------------------------------------------- /plugins/youtube-yts.js: -------------------------------------------------------------------------------- 1 | import yts from 'yt-search' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | if (!text) throw 'Cari apa?' 5 | 6 | await m.react('🕓') 7 | 8 | let results = await yts(text) 9 | let tes = results.all 10 | let teks = results.all.map(v => { 11 | switch (v.type) { 12 | case 'video': return ` 13 | ° *_${v.title}_* 14 | ↳ 🫐 *_Link :_* ${v.url} 15 | ↳ 🕒 *_Duration :_* ${v.timestamp} 16 | ↳ 📥 *_Uploaded :_* ${v.ago} 17 | ↳ 👁 *_Views :_* ${v.views}` 18 | } 19 | }).filter(v => v).join('\n\n◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦◦\n\n') 20 | conn.sendFile(m.chat, tes[0].thumbnail, 'yts.jpeg', teks, m) 21 | } 22 | 23 | handler.help = ['yts '] 24 | handler.tags = ['tools'] 25 | handler.command = /^yts(earch)?$/i 26 | 27 | handler.register = true 28 | 29 | export default handler 30 | -------------------------------------------------------------------------------- /plugins/image-iqc.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const handler = async (m, { conn, args }) => { 4 | let text 5 | if (args.length >= 1) { 6 | text = args.join(" ") 7 | } else if (m.quoted && m.quoted.text) { 8 | text = m.quoted.text 9 | } else throw "Mana teksnya?" 10 | 11 | // URL encode biar aman dipakai di query 12 | const url = `${APIs.ryzumi}/api/image/iqc?text=${encodeURIComponent(text)}` 13 | 14 | const response = await axios.get(url, { responseType: 'arraybuffer' }) 15 | const buffer = Buffer.from(response.data) 16 | 17 | // kirim sebagai file (image/png) 18 | await conn.sendFile(m.chat, buffer, 'iqc.png', '', m) 19 | } 20 | 21 | handler.help = ['iqc'] 22 | handler.tags = ['maker'] 23 | handler.command = /^(iqc)$/i 24 | 25 | handler.register = true 26 | 27 | export default handler 28 | -------------------------------------------------------------------------------- /plugins/sticker-brat.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, command, text }) => { 4 | if (!text || !text.trim()) throw 'Masukkan teks yang valid!' 5 | 6 | try { 7 | let end = '/api/image/brat?text=' 8 | if (/vid|video/i.test(command)) { 9 | end = '/api/image/brat/animated?text=' 10 | } 11 | let url = APIs.ryzumi + end + encodeURIComponent(text.trim()) 12 | const { data } = await axios.get(url, { responseType: 'arraybuffer' }) 13 | await conn.sendSticker(m.chat, data, m) 14 | } catch (err) { 15 | console.error('Error:', err) 16 | await m.reply(`Error: ${err.message || 'Gagal mengambil gambar.'}`) 17 | } 18 | } 19 | 20 | handler.help = ['brat', 'bratvid'] 21 | handler.tags = ['maker'] 22 | handler.command = /^(brat|brat(vid|video))$/i 23 | 24 | handler.register = true 25 | 26 | export default handler 27 | -------------------------------------------------------------------------------- /plugins/tool-ip.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | const handler = async (m, { text, usedPrefix, command }) => { 4 | if (!text) throw `*Example:* ${usedPrefix + command} 112.90.150.204`; 5 | try { 6 | let res = await fetch(`https://ipwho.is/${text}`).then(result => result.json()); 7 | await conn.sendMessage(m.chat, { location: { degreesLatitude: res.latitude, degreesLongitude: res.longitude }},{ ephemeralExpiration: 604800 }); 8 | await delay(2000); 9 | conn.reply(m.chat, JSON.stringify(res, null, 2), m); 10 | } catch (e) { 11 | throw { error: `IP ${text} not found!` }; 12 | } 13 | } 14 | 15 | handler.command = handler.help = ['ip'] 16 | handler.tags = ['tools'] 17 | 18 | handler.limit = true 19 | handler.register = true 20 | 21 | export default handler 22 | 23 | function delay(ms) { 24 | return new Promise(resolve => setTimeout(resolve, ms)); 25 | } -------------------------------------------------------------------------------- /plugins/tool-carbon.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args }) => { 4 | 5 | const code = args[0]; 6 | 7 | if (!code) { 8 | return conn.reply(m.chat, `Please provide the code to generate the image.`, m); 9 | } await m.react('🕓') 10 | 11 | try { 12 | const response = await axios.get(`${APIs.ryzumi}/api/tool/carbon?code=${encodeURIComponent(code)}`, { 13 | responseType: 'arraybuffer' 14 | }); 15 | 16 | conn.sendMessage(m.chat, { image: response.data }, { quoted: m }); 17 | 18 | } catch (error) { 19 | conn.reply(m.chat, `Error occurred while generating the code image.`, m); 20 | } 21 | } 22 | 23 | handler.help = ["carbon"]; 24 | handler.tags = ["ai"]; 25 | handler.command = /^carbon(ify)?$/i; 26 | 27 | handler.register = true 28 | handler.limit = true 29 | 30 | export default handler 31 | -------------------------------------------------------------------------------- /plugins/info-totalfitur.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | 3 | var handler = async (m, { conn, args, command }) => { 4 | let totalf = Object.values(global.plugins).filter( 5 | (v) => v.help && v.tags 6 | ).length; 7 | 8 | let replyMessage = `Total Fitur Bot Saat ini: ${totalf}\n`; 9 | 10 | await conn.reply(m.chat, replyMessage, m, { 11 | contextInfo: { 12 | externalAdReply: { 13 | mediaUrl: '', 14 | mediaType: 2, 15 | description: 'anu', 16 | title: bottime, 17 | body: 'Total Cintaku Padamu', 18 | previewType: 0, 19 | thumbnail: fs.readFileSync("./ryzumi.webp"), 20 | sourceUrl: sig 21 | } 22 | } 23 | }); 24 | } 25 | 26 | handler.tags = ['info'] 27 | handler.command = ['totalfitur'] 28 | 29 | export default handler 30 | -------------------------------------------------------------------------------- /plugins/tool-readviewonce.js: -------------------------------------------------------------------------------- 1 | let handler = async(m) => { 2 | 3 | if (!m.quoted) return m.reply( 4 | "Reply gambar/video yang ingin Anda lihat" 5 | ); 6 | let typ = ["image/jpeg", "video/mp4"] 7 | let regMedia = typ.includes(m.quoted.mimetype); 8 | let view = m.quoted?.viewOnce == true ? true : false 9 | 10 | if (regMedia && view) { 11 | let msg = await m.getQuotedObj()?.message; 12 | let type = Object.keys(msg)[0]; 13 | let media = await m.quoted?.download() || await m.getQuotedObj() 14 | .download(); 15 | if (!media) return m.reply("Media gagal di Eksekusi!") 16 | 17 | await conn.sendFile( 18 | m.chat, media, 'error.mp4', msg[type]?.caption || '', m 19 | ); 20 | } else m.reply("Ini bukan pesan view-once."); 21 | }; 22 | 23 | handler.help = ['read'] 24 | handler.tags = ['tools'] 25 | handler.command = /^read/i 26 | 27 | handler.register = true 28 | 29 | export default handler 30 | -------------------------------------------------------------------------------- /plugins/owner-banuser.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | if (!text) throw 'Siapa yang mau di banned?🗿'; 3 | let who; 4 | if (m.isGroup) { 5 | if (m.mentionedJid.length > 0) { 6 | who = m.mentionedJid[0]; 7 | } else { 8 | let cleanedNumber = text.replace(/\D/g, ''); 9 | who = `${cleanedNumber}@s.whatsapp.net`; 10 | } 11 | } else { 12 | let cleanedNumber = text.replace(/\D/g, ''); 13 | who = `${cleanedNumber}@s.whatsapp.net`; 14 | } 15 | 16 | let users = db.data.users; 17 | if (!users[who]) throw 'Pengguna tidak ditemukan'; 18 | 19 | users[who].banned = true; 20 | conn.reply(m.chat, `Pengguna dengan nomor ${who} telah dibanned!`, m); 21 | } 22 | 23 | handler.help = ['ban '] 24 | handler.tags = ['owner'] 25 | handler.command = /^ban$/i 26 | handler.rowner = true 27 | 28 | export default handler; 29 | -------------------------------------------------------------------------------- /plugins/owner-unbanuser.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | if (!text) throw 'Who wants to be unbanned?' 3 | let who; 4 | if (m.isGroup) { 5 | if (m.mentionedJid.length > 0) { 6 | who = m.mentionedJid[0]; 7 | } else { 8 | let cleanedNumber = text.replace(/\D/g, ''); 9 | who = `${cleanedNumber}@s.whatsapp.net`; 10 | } 11 | } else { 12 | let cleanedNumber = text.replace(/\D/g, ''); 13 | who = `${cleanedNumber}@s.whatsapp.net`; 14 | } 15 | 16 | let users = db.data.users; 17 | if (!users[who]) throw 'Pengguna tidak ditemukan'; 18 | 19 | users[who].banned = false; 20 | conn.reply(m.chat, `Pengguna dengan nomor ${who} telah diunban!`, m); 21 | } 22 | 23 | handler.help = ['unban '] 24 | handler.tags = ['owner'] 25 | handler.command = /^unban(user)?$/i 26 | handler.rowner = true 27 | 28 | export default handler 29 | -------------------------------------------------------------------------------- /plugins/group-tagall.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text, participants }) => { 2 | const fallbackText = ( 3 | m.quoted?.text || 4 | m.quoted?.caption || 5 | m.quoted?.message?.extendedTextMessage?.text || 6 | m.quoted?.message?.conversation || 7 | '' 8 | ).trim() 9 | const msgText = (text || '').trim() || fallbackText 10 | 11 | const users = participants.map(u => u.id).filter(v => v !== conn.user.jid) 12 | const body = users.map(v => '│◦❒ @' + v.replace(/@.+/, '')).join('\n') 13 | const content = `${msgText ? `${msgText}\n\n` : ''}${body}`.trim() 14 | 15 | await conn.reply( 16 | m.chat, 17 | content, 18 | m, 19 | { contextInfo: { mentionedJid: users } } 20 | ) 21 | } 22 | 23 | handler.help = ['tagall'] 24 | handler.tags = ['group'] 25 | handler.command = /^(tagall)$/i 26 | handler.admin = handler.group = true 27 | 28 | export default handler 29 | -------------------------------------------------------------------------------- /plugins/tool-translate.js: -------------------------------------------------------------------------------- 1 | import { translate } from '@vitalets/google-translate-api' 2 | 3 | var handler = async (m, { args, usedPrefix, command }) => { 4 | let lang, text 5 | if (args.length >= 2) { 6 | lang = args[0] ? args[0] : 'id', text = args.slice(1).join(' ') 7 | } else if (m.quoted && m.quoted.text) { 8 | lang = args[0] ? args[0] : 'id', text = m.quoted.text 9 | } else throw `Ex: ${usedPrefix + command} id hello i am robot` 10 | let res = await translate(text, { to: lang }).catch(_ => null) 11 | if (!res) throw `Error : Bahasa"${lang}" Tidak Support` 12 | m.reply(`*Terdeteksi Bahasa:* ${res.raw.src}\n*Ke Bahasa:* ${lang}\n\n*Original Text:* ${res.raw.sentences[0].orig}\n*Terjemahan:* ${res.raw.sentences[0].trans}`.trim()) 13 | } 14 | 15 | handler.help = ['translate'].map(v => v + ' ') 16 | handler.tags = ['tools'] 17 | handler.command = /^(tr(anslate)?)$/i 18 | 19 | handler.register = true 20 | 21 | export default handler -------------------------------------------------------------------------------- /plugins/owner-df.js: -------------------------------------------------------------------------------- 1 | import { tmpdir } from 'os' 2 | import path, { join } from 'path' 3 | import { 4 | readdirSync, 5 | statSync, 6 | unlinkSync, 7 | existsSync, 8 | readFileSync, 9 | watch 10 | } from 'fs' 11 | let handler = async (m, { conn, usedPrefix: _p, __dirname, args, text }) => { 12 | 13 | let ar = Object.keys(plugins) 14 | let ar1 = ar.map(v => v.replace('.js', '')) 15 | if (!text) throw `uhm.. where the text?\n\nexample:\n${usedPrefix + command} info` 16 | if (!ar1.includes(args[0])) return m.reply(`*🗃️ NOT FOUND!*\n==================================\n\n${ar1.map(v => ' ' + v).join`\n`}`) 17 | const file = join(__dirname, '../plugins/' + args[0] + '.js') 18 | unlinkSync(file) 19 | conn.reply(m.chat, `Success deleted "plugins/${args[0]}.js"`, m) 20 | 21 | } 22 | handler.help = ['df'] 23 | handler.tags = ['owner'] 24 | handler.command = /^(df|d(el)?(ete)?(file))$/i 25 | 26 | handler.mods = true 27 | 28 | export default handler 29 | -------------------------------------------------------------------------------- /plugins/main-claimlimit.js: -------------------------------------------------------------------------------- 1 | const rewards = { 2 | limit: 10, 3 | } 4 | const cooldown = 86400000 5 | let handler = async (m,{ conn} ) => { 6 | let user = global.db.data.users[m.sender] 7 | 8 | if (user.role === 'Free user' && user.limit >= 30) { 9 | conn.reply(m.chat, 'Free user only have 30 Limit max', m) 10 | return 11 | } 12 | 13 | if (new Date - user.lastclaim < cooldown) throw `You have already claimed this daily limit!, wait for *${((user.lastclaim + cooldown) - new Date()).toTimeString()}*` 14 | let text = '' 15 | for (let reward of Object.keys(rewards)) { 16 | if (!(reward in user)) continue 17 | user[reward] += rewards[reward] 18 | text += `*+${rewards[reward]}* ${reward}\n` 19 | } 20 | conn.reply(m.chat, text.trim(), m) 21 | user.lastclaim = new Date * 1 22 | } 23 | handler.help = ['claimlimit'] 24 | handler.command = /^(claimlimit)$/i 25 | 26 | handler.cooldown = cooldown 27 | handler.disable = true 28 | 29 | export default handler -------------------------------------------------------------------------------- /plugins/sticker-meme.js: -------------------------------------------------------------------------------- 1 | import { uploadPomf } from '../lib/uploadImage.js' 2 | 3 | let handler = async (m, { conn, text, usedPrefix, command }) => { 4 | let [atas, bawah] = text.split`|` 5 | let q = m.quoted ? m.quoted : m 6 | let mime = (q.msg || q).mimetype || '' 7 | if (!mime) throw `balas gambar dengan perintah\n\n${usedPrefix + command} <${atas ? atas : 'teks atas'}>|<${bawah ? bawah : 'teks bawah'}>` 8 | if (!/image\/(jpe?g|png)/.test(mime)) throw `_*Mime ${mime} tidak didukung!*_` 9 | let img = await q.download() 10 | let url = await uploadPomf(img) 11 | let meme = `https://api.memegen.link/images/custom/${encodeURIComponent(atas ? atas : '')}/${encodeURIComponent(bawah ? bawah : '')}.png?background=${url}`; 12 | conn.sendSticker(m.chat, meme, m) 13 | } 14 | 15 | handler.help = ['smeme |'] 16 | handler.tags = ['tools'] 17 | handler.command = /^(smeme)$/i 18 | 19 | handler.register = true 20 | 21 | export default handler -------------------------------------------------------------------------------- /plugins/ai-animediff.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | 3 | let handler = async (m, { conn, text, usedPrefix, command }) => { 4 | if (!text) throw `This command generates images from text prompts.\n\nExample usage:\n${usedPrefix + command} anime girl with glasses, pink short hair, in a uniform, anime style, full body, bokeh`; 5 | await m.react('🕓') 6 | 7 | const apiUrl = `${APIs.ryzumi}/api/ai/text2img?prompt=${encodeURIComponent(text)}`; 8 | try { 9 | let response = await fetch(apiUrl); 10 | let imageBuffer = await response.buffer(); 11 | await conn.sendFile(m.chat, imageBuffer, 'image.jpg', wm, m); 12 | } catch (error) { 13 | conn.reply(m.chat, 'All API URLs failed. Please try again later.', m); 14 | } 15 | } 16 | 17 | handler.help = ['txt2img'] 18 | handler.tags = ['ai'] 19 | handler.command = /^(text2img|txt2img)$/i 20 | handler.premium = false 21 | handler.limit = 15 22 | handler.register = true 23 | 24 | export default handler -------------------------------------------------------------------------------- /plugins/cmd-set.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text, usedPrefix, command }) => { 2 | db.data.sticker = db.data.sticker || {} 3 | if (!m.quoted) throw 'Balas stiker dengan perintah *${usedPrefix + command}*' 4 | if (!m.quoted.fileSha256) throw 'SHA256 Hash Missing' 5 | if (!text) throw `Penggunaan:\n${usedPrefix + command} \n\nContoh:\n${usedPrefix + command} tes` 6 | let sticker = db.data.sticker 7 | let hash = Buffer.from(m.quoted.fileSha256).toString('hex') 8 | if (sticker[hash] && sticker[hash].locked) throw 'Kamu tidak memiliki izin untuk mengubah perintah stiker ini' 9 | sticker[hash] = { 10 | text, 11 | mentionedJid: m.mentionedJid, 12 | creator: m.sender, 13 | at: + new Date, 14 | locked: false, 15 | } 16 | m.reply(`Success!`) 17 | } 18 | 19 | 20 | handler.help = ['cmd'].map(v => 'set' + v + ' ') 21 | handler.tags = ['database'] 22 | handler.command = ['setcmd'] 23 | 24 | export default handler 25 | -------------------------------------------------------------------------------- /plugins/stalk-instagram.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | if (!text || !text.trim()) throw 'Masukkan username yang valid!' 5 | let username = text.trim() 6 | 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | const { data } = await axios.get(`${APIs.ryzumi}/api/stalk/instagram?username=${username}`) 12 | 13 | let caption = ` 14 | Name: ${data.name} 15 | Username: ${data.username} 16 | Bio: ${data.bio} 17 | Followers: ${data.followers} 18 | Following: ${data.following} 19 | Posts: ${data.posts} 20 | Avatar: ${data.avatar} 21 | `.trim() 22 | 23 | await conn.sendMessage(m.chat, { image: { url: data.avatar }, caption }, { quoted: m }) 24 | } catch (err) { 25 | m.reply('Error: ' + err.message) 26 | } 27 | } 28 | 29 | handler.help = ['igstalk'] 30 | handler.tags = ['stalk'] 31 | handler.command = /^(igstalk|instagramstalk)$/i 32 | 33 | handler.register = true 34 | handler.limit = true 35 | 36 | export default handler 37 | -------------------------------------------------------------------------------- /plugins/host-bcgcb.js: -------------------------------------------------------------------------------- 1 | var handler = async (m, { conn, text } ) => { 2 | let groups = Object.entries(conn.chats).filter(([jid, chat]) => jid.endsWith('@g.us') && chat.isChats && !chat.metadata?.read_only && !chat.metadata?.announce).map(v => v[0]) 3 | 4 | conn.reply(m.chat, `_Mengirim pesan broadcast ke ${groups.length} grup_`, m) 5 | for (let id of groups) { 6 | let member = (await conn.groupMetadata(id)).participants.map(v => v.jid) 7 | conn.sendFile(id, thumbbc, 'Thumb.jpg', '────━┅ *BROADCAST* ┅━────\n' + text, m, { contextInfo: { 8 | externalAdReply: { showAdAttribution: true, 9 | title: `${htjava} BROADCAST`, 10 | body: titlebot, 11 | description: wm2, 12 | mediaType: 2, 13 | thumbnail: await getBuffer(thumbbc), 14 | mediaUrl: sig 15 | } 16 | } 17 | }) 18 | } 19 | m.reply('*D O N E !*') 20 | } 21 | handler.command = ['bcgcb'] 22 | handler.tags = ['host'] 23 | handler.help = ['bcgcb'] 24 | 25 | handler.rowner = true 26 | 27 | export default handler 28 | -------------------------------------------------------------------------------- /plugins/info-report.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text, usedPrefix, command }) => { 2 | if (!text) throw `kalo kamu nemu pesan eror, lapor pake perintah ini\n\ncontoh:\n${usedPrefix + command} selamat siang owner, sy menemukan eror seperti berikut ` 3 | if (text.length < 10) throw `Laporan terlalu pendek, minimal 10 karakter!` 4 | if (text.length > 1000) throw `Laporan terlalu panjang, maksimal 1000 karakter!` 5 | let teks = `*${command.toUpperCase()}!*\n\nDari : *@${m.sender.split`@`[0]}*\n\nPesan : ${text}\n` 6 | conn.reply(global.nomorown + '@s.whatsapp.net', m.quoted ? teks + m.quoted.text : teks, null, { 7 | contextInfo: { 8 | mentionedJid: [m.sender] 9 | } 10 | }) 11 | m.reply(`_Pesan terkirim kepemilik bot, jika ${command.toLowerCase()} hanya main-main tidak akan ditanggapi._`) 12 | } 13 | handler.help = ['report'] 14 | handler.tags = ['info'] 15 | handler.command = /^(report)$/i 16 | 17 | handler.register = true 18 | handler.disable = false 19 | 20 | export default handler -------------------------------------------------------------------------------- /plugins/info-gempa.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | const link = 'https://data.bmkg.go.id/DataMKG/TEWS/' 4 | 5 | let handler = async (m, { conn, text, usedPrefix, command }) => { 6 | try { 7 | let res = await fetch(link + 'autogempa.json') 8 | let anu = await res.json() 9 | anu = anu.Infogempa.gempa 10 | let txt = `*${anu.Wilayah}*\n\n` 11 | txt += `Tanggal : ${anu.Tanggal}\n` 12 | txt += `Waktu : ${anu.Jam}\n` 13 | txt += `Potensi : *${anu.Potensi}*\n\n` 14 | txt += `Magnitude : ${anu.Magnitude}\n` 15 | txt += `Kedalaman : ${anu.Kedalaman}\n` 16 | txt += `Koordinat : ${anu.Coordinates}${anu.Dirasakan.length > 3 ? `\nDirasakan : ${anu.Dirasakan}` : ''}` 17 | await conn.sendMessage(m.chat, { image: { url: link + anu.Shakemap }, caption: txt }, { quoted: m }) 18 | } catch (e) { 19 | console.log(e) 20 | m.reply(`[!] Fitur Error.`) 21 | } 22 | } 23 | 24 | handler.help = ['gempa'] 25 | handler.tags = ['info'] 26 | handler.command = /^(gempa)$/i 27 | 28 | handler.premium = false 29 | handler.limit = false 30 | 31 | export default handler -------------------------------------------------------------------------------- /plugins/ai-flux.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | 3 | let handler = async (m, { conn, text, usedPrefix, command }) => { 4 | if (!text) throw `This command generates images from text prompts.\n\nExample usage:\n${usedPrefix + command} anime girl with glasses, pink short hair, in a uniform, anime style, full body, bokeh`; 5 | await m.react('🕓') 6 | 7 | const apiUrl = `${APIs.ryzumi}/api/ai/v2/text2img?prompt=${encodeURIComponent(text)}`; 8 | try { 9 | let response = await fetch(apiUrl, { 10 | headers: { 11 | accept: 'image/png' 12 | } 13 | }); 14 | let imageBuffer = Buffer.from(await response.arrayBuffer()); 15 | 16 | await conn.sendFile(m.chat, imageBuffer, 'image.jpg', wm, m); 17 | } catch (error) { 18 | conn.reply(m.chat, error.message, m); 19 | } 20 | } 21 | 22 | handler.help = ['flux'] 23 | handler.tags = ['ai'] 24 | handler.command = /^(flux|flux)$/i 25 | handler.premium = false 26 | handler.limit = 15 27 | handler.register = true 28 | 29 | export default handler 30 | -------------------------------------------------------------------------------- /plugins/ai-colorize.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | let handler = async (m, { conn, usedPrefix }) => { 5 | try { 6 | await m.react('🕓') 7 | let q = m.quoted ? m.quoted : m; 8 | let mime = (q.msg || q).mimetype || ''; 9 | if (!mime) throw `Kirim/Reply Gambar dengan caption ${usedPrefix}colorize`; 10 | 11 | 12 | let media = await q.download(); 13 | let url = await uploadPomf(media); 14 | 15 | let response = await fetch(`${APIs.ryzumi}/api/ai/colorize?url=${url}`); 16 | if (!response.ok) throw new Error('Failed to fetch image from API'); 17 | let hasil = Buffer.from(await response.arrayBuffer()); 18 | 19 | await conn.sendFile(m.chat, hasil, 'kolor.jpg', global.wm, m); 20 | } catch (error) { 21 | m.reply(`Error: ${error}`); 22 | } 23 | }; 24 | 25 | handler.help = ['colorize']; 26 | handler.tags = ['ai']; 27 | handler.command = /^(colorize)$/i; 28 | handler.register = true 29 | handler.limit = 3 30 | 31 | export default handler 32 | -------------------------------------------------------------------------------- /plugins/expired-cek.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args, usedPrefix, command }) => { 2 | if (global.db.data.chats[m.chat].expired < 1) throw `Group ini tidak diatur untuk kedaluwarsa!` 3 | let who; 4 | if (m.isGroup) who = args[0] ? args[0] : m.chat; 5 | else who = args[0]; 6 | 7 | var now = new Date() * 1; 8 | 9 | conn.reply(m.chat, `*⌛️ ᴇxᴘɪʀᴇᴅ ⌛️*\n\n${msToDate(global.db.data.chats[who].expired - now)}`, m); 10 | } 11 | 12 | handler.help = ['cekexpired'] 13 | handler.tags = ['group'] 14 | handler.command = /^(cekexpired|cekkadaluarsa|checkexpired|checkkadaluarsa)$/i 15 | handler.group = true 16 | 17 | export default handler 18 | 19 | function msToDate(ms) { 20 | let temp = ms 21 | let days = Math.floor(ms / (24 * 60 * 60 * 1000)); 22 | let daysms = ms % (24 * 60 * 60 * 1000); 23 | let hours = Math.floor((daysms) / (60 * 60 * 1000)); 24 | let hoursms = ms % (60 * 60 * 1000); 25 | let minutes = Math.floor((hoursms) / (60 * 1000)); 26 | let minutesms = ms % (60 * 1000); 27 | return `${days} hari ${hours} jam ${minutes} menit`; 28 | } 29 | -------------------------------------------------------------------------------- /plugins/owner-gp.js: -------------------------------------------------------------------------------- 1 | import cp, { exec as _exec } from 'child_process' 2 | import { promisify } from 'util' 3 | let exec = promisify(_exec).bind(cp) 4 | 5 | let handler = async (m, { conn, isROwner, usedPrefix, command, text }) => { 6 | 7 | if (!isROwner) return 8 | await m.react('🕓') 9 | let ar = Object.keys(plugins) 10 | let ar1 = ar.map(v => v.replace('.js', '')) 11 | if (!text) throw `uhm.. where the text?\n\nexample:\n${usedPrefix + command} info` 12 | if (!ar1.includes(text)) return m.reply(`*🗃️ NOT FOUND!*\n==================================\n\n${ar1.map(v => ' ' + v).join`\n`}`) 13 | let o 14 | try { 15 | o = await exec('cat plugins/' + text + '.js') 16 | } catch (e) { 17 | o = e 18 | } finally { 19 | let { stdout, stderr } = o 20 | if (stdout.trim()) m.reply(stdout) 21 | if (stderr.trim()) m.reply(stderr) 22 | } 23 | } 24 | handler.help = ['getplugin'].map(v => v + ' ') 25 | handler.tags = ['owner'] 26 | handler.command = /^(getplugin|gp)$/i 27 | handler.rowner = true 28 | 29 | export default handler -------------------------------------------------------------------------------- /plugins/ai-img2txt.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | let handler = async (m, { conn, usedPrefix }) => { 5 | try { 6 | await m.react('🕓') 7 | let q = m.quoted ? m.quoted : m; 8 | let mime = (q.msg || q).mimetype || ''; 9 | if (!mime) throw `Kirim/Reply Gambar dengan caption ${usedPrefix}img2txt`; 10 | 11 | 12 | let media = await q.download(); 13 | let url = await uploadPomf(media); 14 | 15 | let response = await fetch(`${APIs.ryzumi}/api/ai/image2txt?url=${url}`); 16 | if (!response.ok) throw new Error('Failed to fetch data from API'); 17 | 18 | let { result: hasil } = await response.json(); 19 | 20 | await conn.sendMessage(m.chat, { text: hasil }, { quoted: m }); 21 | } catch (error) { 22 | m.reply(`Error: ${error}`); 23 | } 24 | }; 25 | 26 | handler.help = ['toprompt']; 27 | handler.tags = ['ai']; 28 | handler.command = /^(toprompt|img2txt)$/i; 29 | 30 | handler.register = true 31 | handler.limit = 5 32 | 33 | export default handler 34 | -------------------------------------------------------------------------------- /plugins/broadcastall.js: -------------------------------------------------------------------------------- 1 | import { randomBytes } from 'crypto' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | let chats = Object.entries(conn.chats).filter(([_, chat]) => chat.isChats).map(v => v[0]) 5 | let cc = conn.serializeM(text ? m : m.quoted ? await m.getQuotedObj() : false || m) 6 | let teks = text ? text : cc.text 7 | conn.reply(m.chat, `_Mengirim pesan broadcast ke ${chats.length} chat_`, m) 8 | for (let id of chats) await conn.copyNForward(id, conn.cMod(m.chat, cc, /bc|broadcast/i.test(teks) ? `${htki} *BROADCAST* ${htka}\n` + teks : `${htki} *BROADCAST* ${htka}\n` + teks + '\n' + readMore + '\n\n' + botdate), true).catch(_ => _) 9 | m.reply('Selesai Broadcast All Chat :)') 10 | } 11 | handler.help = ['broadcast', 'bc'].map(v => v + ' ') 12 | handler.tags = ['owner'] 13 | handler.command = /^(broadcast|bc)$/i 14 | 15 | handler.owner = true 16 | 17 | export default handler 18 | 19 | const more = String.fromCharCode(8206) 20 | const readMore = more.repeat(4001) 21 | 22 | const randomID = length => randomBytes(Math.ceil(length * .5)).toString('hex').slice(0, length) 23 | -------------------------------------------------------------------------------- /plugins/_cmdWithMedia.js: -------------------------------------------------------------------------------- 1 | import { 2 | proto, 3 | generateWAMessage, 4 | areJidsSameUser 5 | } from '@whiskeysockets/baileys' 6 | 7 | export async function all(m, chatUpdate) { 8 | if (m.isBaileys) return 9 | if (!m.message) return 10 | if (!m.msg.fileSha256) return 11 | if (!(Buffer.from(m.msg.fileSha256).toString('hex') in global.db.data.sticker)) return 12 | 13 | let hash = global.db.data.sticker[Buffer.from(m.msg.fileSha256).toString('hex')] 14 | let { text, mentionedJid } = hash 15 | let messages = await generateWAMessage(m.sender, { text: text, mentions: mentionedJid }, { 16 | userJid: this.user.id, 17 | quoted: m.quoted && m.quoted.fakeObj 18 | }) 19 | messages.key.fromMe = areJidsSameUser(m.chat, this.user.id) 20 | messages.key.id = m.key.id 21 | messages.pushName = m.pushName 22 | if (m.isGroup) messages.key.participant = m.sender 23 | let msg = { 24 | ...chatUpdate, 25 | messages: [proto.WebMessageInfo.create(messages)], 26 | type: 'append' 27 | } 28 | this.ev.emit('messages.upsert', msg) 29 | } 30 | -------------------------------------------------------------------------------- /plugins/broadcastchats.js: -------------------------------------------------------------------------------- 1 | import { randomBytes } from 'crypto' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | let chats = Object.entries(conn.chats).filter(([jid, chat]) => !jid.endsWith('@g.us') && chat.isChats).map(v => v[0]) 5 | let cc = conn.serializeM(text ? m : m.quoted ? await m.getQuotedObj() : false || m) 6 | let teks = text ? text : cc.text 7 | conn.reply(m.chat, `_Mengirim broadcast ke ${chats.length} chat_`, m) 8 | for (let id of chats) await conn.copyNForward(id, conn.cMod(m.chat, cc, /bc|broadcast/i.test(teks) ? teks : teks + '\n' + readMore + '「 ' + author + ' All Chat Broadcast 」\n' + randomID(32)), true).catch(_ => _) 9 | m.reply('Selesai Broadcast All Chat :)') 10 | } 11 | handler.help = ['broadcastchats', 'bcchats'].map(v => v + ' ') 12 | handler.tags = ['owner'] 13 | handler.command = /^(broadcastchats?|bcc(hats?)?)$/i 14 | 15 | handler.owner = true 16 | 17 | export default handler 18 | 19 | const more = String.fromCharCode(8206) 20 | const readMore = more.repeat(4001) 21 | 22 | const randomID = length => randomBytes(Math.ceil(length * .5)).toString('hex').slice(0, length) 23 | -------------------------------------------------------------------------------- /plugins/sticker-tovideo.js: -------------------------------------------------------------------------------- 1 | import { webp2mp4 } from '../lib/webp2mp4.js' 2 | import { ffmpeg } from '../lib/converter.js' 3 | let handler = async (m, { conn, usedPrefix, command }) => { 4 | if (!m.quoted) throw `Balas stiker/audio yang ingin diubah menjadi video dengan perintah ${usedPrefix + command}` 5 | let mime = m.quoted.mimetype || '' 6 | if (!/webp|audio/.test(mime)) throw `Balas stiker/audio yang ingin diubah menjadi video dengan perintah ${usedPrefix + command}` 7 | let media = await m.quoted.download() 8 | let out = Buffer.alloc(0) 9 | if (/webp/.test(mime)) { 10 | out = await webp2mp4(media) 11 | } else if (/audio/.test(mime)) { 12 | out = await ffmpeg(media, [ 13 | '-filter_complex', 'color', 14 | '-pix_fmt', 'yuv420p', 15 | '-crf', '51', 16 | '-c:a', 'copy', 17 | '-shortest' 18 | ], 'mp3', 'mp4') 19 | } 20 | await conn.sendFile(m.chat, out, 'out.mp4', '*DONE*', m, 0, { thumbnail: out }) 21 | } 22 | 23 | handler.help = ['tovideo'] 24 | handler.tags = ['maker'] 25 | handler.command = ['tovideo', 'tomp4'] 26 | 27 | handler.register = true 28 | handler.limit = 2 29 | 30 | export default handler -------------------------------------------------------------------------------- /plugins/sticker-emojimix.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | let handler = async (m, { conn, text, usedPrefix, command }) => { 4 | if (!text) throw `*⛌ Masukan Emoji Yg ingin kamu gabungkan*\n\n*• Example:*\n- ${usedPrefix + command} 😂+😂\n- ${usedPrefix + command} 😂 😂\n\n[ minimal 2 emoji ]`; 5 | 6 | let emojis = text.split(/[\+\s]/).filter(Boolean); 7 | if (emojis.length < 2) throw 'Masukkan minimal 2 emoji untuk di-mix'; 8 | if (emojis.length > 2) throw 'Max 2 emoji untuk di-mix'; 9 | 10 | const anu = await (await fetch(`https://tenor.googleapis.com/v2/featured?key=AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ&contentfilter=high&media_filter=png_transparent&component=proactive&collection=emoji_kitchen_v5&q=${encodeURIComponent(emojis.join('_'))}`)).json(); 11 | 12 | if (!anu.results[0]) throw 'Kombinasi Emojimix Tidak Ditemukan'; 13 | 14 | let emix = anu.results[0].media_formats.png_transparent.url; 15 | conn.sendSticker(m.chat, emix, m) 16 | }; 17 | 18 | handler.help = ['emojimix'] 19 | handler.tags = ['maker'] 20 | handler.command = /^(emojimix|emix)$/i 21 | handler.register = true 22 | 23 | export default handler -------------------------------------------------------------------------------- /plugins/downloader-danbooru.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import * as cheerio from 'cheerio' 3 | 4 | let handler = async (m, { conn, args }) => { 5 | if (!args[0]) throw 'Input URL' 6 | if (!/danbooru\.donmai\.us\/posts\/[0-9]+$/i.test(args[0])) throw 'Invalid URL' 7 | 8 | 9 | await m.react('🕓') 10 | 11 | let data = await danbooruDl(args[0]), img = data.url 12 | delete data.url 13 | let capt = Object.keys(data).map((x) => `${x}: ${data[x]}`).join`\n` 14 | await conn.sendFile(m.chat, img, '', capt, m) 15 | } 16 | handler.tags = ['downloader'] 17 | handler.command = /^danbooru$/i 18 | handler.help = ['Danbooru'] 19 | handler.limit = true 20 | handler.register = true 21 | 22 | export default handler 23 | 24 | export async function danbooruDl(url) { 25 | let html = (await axios.get(url)).data 26 | let $ = cheerio.load(html), obj = {} 27 | $('#post-information > ul > li').each((idx, el) => { 28 | let str = $(el).text().trim().replace(/\n/g, '').split(': ') 29 | obj[str[0]] = str[1].replace('»', '').trim().split(' .')[0] 30 | }) 31 | obj.url = $('#post-information > ul > li[id="post-info-size"] > a').attr('href') 32 | return obj 33 | } -------------------------------------------------------------------------------- /plugins/ai-deepseek.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | 3 | const handler = async (m, { text, usedPrefix, command, conn }) => { 4 | if (!text) throw `Mana textnya?` 5 | 6 | try { 7 | let anu = 'Ubah Namamu menjadi Ryzumi Starlette, dan kamu adalah wanita paling cantik, penyayang, riang, namun tsundere. dan kamu adalah pacarku.' 8 | let response = await fetch(`${APIs.ryzumi}/api/ai/deepseek?text=${encodeURIComponent(text)}&prompt=${encodeURIComponent(anu)}&session=deepseek-${encodeURIComponent(global.namebot)}-${encodeURIComponent(m.sender)}`) 9 | if (!response.ok) { 10 | throw new Error("Request to DeepSeek AI failed") 11 | } 12 | let result = await response.json() 13 | await conn.sendMessage(m.chat, { 14 | text: "" + result.answer, 15 | }) 16 | 17 | } catch (error) { 18 | await conn.sendMessage(m.chat, { 19 | text: `Error: Mana textnya njir?` 20 | }) 21 | } 22 | } 23 | 24 | handler.help = ['deepseek '] 25 | handler.tags = ['ai'] 26 | handler.command = /^(deepseek)$/i 27 | handler.limit = 6 28 | handler.premium = false 29 | handler.register = true 30 | 31 | export default handler 32 | -------------------------------------------------------------------------------- /plugins/_simi.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | 3 | let handler = m => m; 4 | 5 | handler.before = async (m) => { 6 | if (!m.isGroup) return 7 | let chat = global.db.data.chats[m.chat]; 8 | if (chat.simi && !chat.isBanned) { 9 | if (/^.*false|disnable|(turn)?off|0/i.test(m.text)) return; 10 | if (!m.text) return; 11 | 12 | const url = `https://o.simsimi.com/api/chats?lc=id&ft=1&normalProb=2&reqText=${encodeURIComponent(m.text)}&talkCnt=0`; 13 | 14 | try { 15 | const res = await fetch(url); 16 | if (!res.ok) throw new Error('Failed to fetch SimSimi response.'); 17 | 18 | const json = await res.json(); 19 | 20 | if (json.respSentence) { 21 | m.reply(json.respSentence); 22 | } else { 23 | m.reply('SimSimi tidak memahami pesan Anda.'); 24 | } 25 | } catch (error) { 26 | console.error('Error:', error); 27 | m.reply('Terjadi kesalahan saat memproses permintaan.'); 28 | } 29 | 30 | return !0; 31 | } 32 | return true; 33 | }; 34 | 35 | export default handler; 36 | -------------------------------------------------------------------------------- /plugins/expired-del.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args, usedPrefix, command }) => { 2 | 3 | let who 4 | if (m.isGroup) who = args[1] ? args[1] : m.chat 5 | else who = args[1] 6 | 7 | if (new Date() * 1 < global.db.data.chats[who].expired) global.db.data.chats[who].expired = false 8 | else global.db.data.chats[who].expired = false 9 | conn.reply(m.chat, `Berhasil menghapus hari kadaluarsa untuk Grup ini`, m) 10 | } 11 | handler.help = ['delexpired'] 12 | handler.tags = ['owner'] 13 | handler.command = /^(delexpired|delsewa)$/i 14 | handler.rowner = true 15 | handler.group = true 16 | 17 | export default handler 18 | 19 | function msToDate(ms) { 20 | let temp = ms 21 | let days = Math.floor(ms / (24 * 60 * 60 * 1000)); 22 | let daysms = ms % (24 * 60 * 60 * 1000); 23 | let hours = Math.floor((daysms) / (60 * 60 * 1000)); 24 | let hoursms = ms % (60 * 60 * 1000); 25 | let minutes = Math.floor((hoursms) / (60 * 1000)); 26 | let minutesms = ms % (60 * 1000); 27 | let sec = Math.floor((minutesms) / (1000)); 28 | return days + " hari " + hours + " jam " + minutes + " menit"; 29 | // +minutes+":"+sec; 30 | } 31 | -------------------------------------------------------------------------------- /plugins/broadcastgroups.js: -------------------------------------------------------------------------------- 1 | import { randomBytes } from 'crypto' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | let groups = Object.entries(conn.chats).filter(([jid, chat]) => jid.endsWith('@g.us') && chat.isChats && !chat.metadata?.read_only && !chat.metadata?.announce).map(v => v[0]) 5 | let cc = text ? m : m.quoted ? await m.getQuotedObj() : false || m 6 | let teks = text ? text : cc.text 7 | conn.reply(m.chat, `_Mengirim pesan broadcast ke ${groups.length} grup_`, m) 8 | for (let id of groups) await conn.copyNForward(id, conn.cMod(m.chat, cc, /bc|broadcast/i.test(teks) ? `${htki} *BROADCAST* ${htka}\n` + teks : `${htki} *BROADCAST* ${htka}\n` + teks + '\n' + readMore + '\n\n' + botdate), true).catch(_ => _) 9 | m.reply('Selesai Broadcast All Group :)') 10 | } 11 | handler.help = ['broadcastgroup', 'bcgc'].map(v => v + ' ') 12 | handler.tags = ['owner'] 13 | handler.command = /^(broadcast|bc)(group|grup|gc)$/i 14 | 15 | handler.owner = true 16 | 17 | export default handler 18 | 19 | const more = String.fromCharCode(8206) 20 | const readMore = more.repeat(4001) 21 | 22 | const randomID = length => randomBytes(Math.ceil(length * .5)).toString('hex').slice(0, length) -------------------------------------------------------------------------------- /plugins/downloader-soundcloud.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args, usedPrefix, command }) => { 4 | if (!args[0]) throw `Usage: ${usedPrefix + command} ` 5 | 6 | 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | const { data } = await axios.get(`${APIs.ryzumi}/api/downloader/soundcloud?url=${encodeURIComponent(args[0])}`) 12 | const { title, thumbnail, filesize, download_url } = data || {} 13 | 14 | if (!download_url || !title) throw 'Failed to fetch SoundCloud data. Please verify the URL.' 15 | 16 | conn.sendMessage(m.chat, { 17 | document: { url: download_url }, 18 | mimetype: 'audio/mpeg', 19 | fileName: `${title}.mp3`, 20 | caption: ` 21 | *Title:* ${title} 22 | *Filesize:* ${filesize || '-'} bytes 23 | *Thumbnail:* ${thumbnail || '-'} 24 | *Source:* ${args[0]} 25 | `.trim(), 26 | }, { quoted: m }) 27 | } catch (err) { 28 | console.error(err) 29 | throw `Error: ${err?.message || err}` 30 | } 31 | } 32 | 33 | handler.help = ['soundcloud '] 34 | handler.tags = ['downloader'] 35 | handler.command = /^(soundcloud(dl)?|sc(dl)?)$/i 36 | handler.limit = 2 37 | handler.register = true 38 | 39 | export default handler 40 | -------------------------------------------------------------------------------- /plugins/downloader-mediafire.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args, usedPrefix, command }) => { 4 | if (!args[0]) throw `Gunakan contoh: ${usedPrefix}${command} https://www.mediafire.com/file/in5j3u2zwoq1x33/BLUR_BLUR_ASIK.zip/file`; 5 | 6 | await m.react('🕓') 7 | 8 | try { 9 | let res = await axios.get(`${APIs.ryzumi}/api/downloader/mediafire?url=${encodeURIComponent(args[0])}`); 10 | let { status, data, error } = res.data; 11 | 12 | if (!status || !data || !data.downloadUrl) throw 'Gagal mengambil link download. Coba lagi nanti.'; 13 | 14 | let { filename, filesize, downloadUrl } = data; 15 | 16 | m.reply(` 17 | *📁 Nama File:* ${filename} 18 | *📦 Ukuran:* ${filesize} 19 | `.trim()); 20 | await conn.sendFile(m.chat, downloadUrl, filename, '', m, null, { asDocument: true }); 21 | } catch (e) { 22 | throw 'Terjadi kesalahan: ' + (e?.message || e); 23 | } 24 | }; 25 | 26 | handler.help = ['mediafire'].map(v => v + ' '); 27 | handler.tags = ['downloader']; 28 | handler.command = /^(mediafire|mf)$/i; 29 | handler.limit = true 30 | handler.register = true 31 | 32 | export default handler 33 | -------------------------------------------------------------------------------- /plugins/stalk_tiktok.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | if (!text || !text.trim()) throw 'Masukkan username yang valid!' 5 | let username = text.trim() 6 | 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | const { data } = await axios.get(`${APIs.ryzumi}/api/stalk/tiktok?username=${username}`) 12 | const user = data.userInfo 13 | 14 | let caption = ` 15 | ID: ${user.id} 16 | Username: ${user.username} 17 | Name: ${user.name} 18 | Bio: ${user.bio} 19 | Verified: ${user.verified ? 'Yes' : 'No'} 20 | Followers: ${user.totalFollowers} 21 | Following: ${user.totalFollowing} 22 | Likes: ${user.totalLikes} 23 | Videos: ${user.totalVideos} 24 | Friends: ${user.totalFriends} 25 | Avatar: ${user.avatar} 26 | `.trim() 27 | 28 | await conn.sendMessage(m.chat, { image: { url: user.avatar }, caption }, { quoted: m }) 29 | } catch (err) { 30 | m.reply('Error: ' + err.message) 31 | } 32 | } 33 | 34 | handler.help = ['ttstalk'] 35 | handler.tags = ['stalk'] 36 | handler.command = /^(ttstalk|tiktokstalk)$/i 37 | 38 | handler.register = true 39 | handler.limit = true 40 | 41 | export default handler 42 | -------------------------------------------------------------------------------- /plugins/ai-toanime.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | let handler = async (m, { conn, usedPrefix, command, text }) => { 5 | try { 6 | await m.react('🕓') 7 | let args = text.trim().split(/\s+/); 8 | let style = args[1] || "anime"; 9 | 10 | let q = m.quoted ? m.quoted : m; 11 | let mime = (q.msg || q).mimetype || ''; 12 | if (!mime) throw `Kirim/Reply Gambar dengan caption ${usedPrefix}toanime`; 13 | 14 | 15 | let media = await q.download(); 16 | let url = await uploadPomf(media); 17 | 18 | let response = await fetch(`${APIs.ryzumi}/api/ai/toanime?url=${url}&style=${style}`); 19 | if (!response.ok) throw new Error('Failed to fetch image from API'); 20 | let hasil = Buffer.from(await response.arrayBuffer()); 21 | 22 | await conn.sendFile(m.chat, hasil, 'toanime.jpg', global.wm, m); 23 | } catch (error) { 24 | m.reply(`Error: ${error}`); 25 | } 26 | }; 27 | 28 | handler.help = ['toanime']; 29 | handler.tags = ['ai']; 30 | handler.command = /^(toanime)$/i; 31 | 32 | handler.register = true 33 | handler.limit = 8 34 | 35 | export default handler 36 | -------------------------------------------------------------------------------- /plugins/sticker-qc.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const handler = async (m, { conn, args }) => { 4 | let text 5 | if (args.length >= 1) { 6 | text = args.join(" ") 7 | } else if (m.quoted && m.quoted.text) { 8 | text = m.quoted.text 9 | } else throw "Mana teksnya?" 10 | 11 | const who = m.mentionedJid && m.mentionedJid[0] 12 | ? m.mentionedJid[0] 13 | : m.fromMe 14 | ? conn.user.jid 15 | : m.sender 16 | 17 | const orang = text 18 | const pp = await conn.profilePictureUrl(who, 'image').catch(_ => './src/avatar_contact.png') 19 | const name = await conn.getName(who) 20 | 21 | const url = `${APIs.ryzumi}/api/image/quotly?` + 22 | `text=${encodeURIComponent(orang)}` + 23 | `&name=${encodeURIComponent(name)}` + 24 | `&avatar=${encodeURIComponent(pp)}` 25 | 26 | const response = await axios.get(url, { responseType: 'arraybuffer' }) 27 | const buffer = Buffer.from(response.data) 28 | 29 | conn.sendSticker(m.chat, buffer, m) 30 | } 31 | 32 | handler.help = ['qc'] 33 | handler.tags = ['maker'] 34 | handler.command = /^(qc)$/i 35 | 36 | handler.register = true 37 | 38 | export default handler 39 | -------------------------------------------------------------------------------- /lib/levelling.js: -------------------------------------------------------------------------------- 1 | export const growth = Math.pow(Math.PI / Math.E, 1.618) * Math.E * .75 2 | export function xpRange(level, multiplier = global.multiplier || 1) { 3 | if (level < 0) 4 | throw new TypeError('level tidak boleh bernilai negatif dari') 5 | level = Math.floor(level) 6 | let min = level === 0 ? 0 : Math.round(Math.pow(level, growth) * multiplier) + 1 7 | let max = Math.round(Math.pow(++level, growth) * multiplier) 8 | return { 9 | min, 10 | max, 11 | xp: max - min 12 | } 13 | } 14 | export function findLevel(xp, multiplier = global.multiplier || 1) { 15 | if (xp === Infinity) 16 | return Infinity 17 | if (isNaN(xp)) 18 | return NaN 19 | if (xp <= 0) 20 | return -1 21 | let level = 0 22 | do 23 | level++ 24 | while (xpRange(level, multiplier).min <= xp) 25 | return --level 26 | } 27 | export function canLevelUp(level, xp, multiplier = global.multiplier || 1) { 28 | if (level < 0) 29 | return false 30 | if (xp === Infinity) 31 | return true 32 | if (isNaN(xp)) 33 | return false 34 | if (xp <= 0) 35 | return false 36 | return level < findLevel(xp, multiplier) 37 | } 38 | -------------------------------------------------------------------------------- /plugins/main-register.js: -------------------------------------------------------------------------------- 1 | import { createHash } from 'crypto' 2 | 3 | let Reg = /\|?(.*)([.|] *?)([0-9]*)$/i 4 | let handler = async function (m, { text, usedPrefix }) { 5 | let user = global.db.data.users[m.sender] 6 | if (user.registered === true) throw `Anda sudah terdaftar\nMau daftar ulang? ${usedPrefix}unreg ` 7 | if (!Reg.test(text)) throw `Format salah\n*${usedPrefix}register nama.umur*` 8 | let [_, name, splitter, age] = text.match(Reg) 9 | if (!name) throw 'Nama tidak boleh kosong (Alphanumeric)' 10 | if (!age) throw 'Umur tidak boleh kosong (Angka)' 11 | age = parseInt(age) 12 | if (age > 60) throw 'Tuwa Bangka Mana Paham Teknologi😂' 13 | if (age < 16) throw 'Esempe dilarang masuk 😂' 14 | user.name = name.trim() 15 | user.age = age 16 | user.regTime = Date.now() 17 | user.registered = true 18 | let sn = createHash('md5').update(m.sender).digest('hex') 19 | m.reply(` 20 | Daftar berhasil! 21 | 22 | ╭─「 Info 」 23 | │ Nama: ${name} 24 | │ Umur: ${age} tahun 25 | ╰──── 26 | Serial Number: 27 | ${sn} 28 | `.trim()) 29 | } 30 | 31 | handler.help = ['daftar', 'register'].map(v => v + ' .') 32 | handler.command = /^(daftar|reg(ister)?)$/i 33 | handler.private = true 34 | 35 | export default handler -------------------------------------------------------------------------------- /plugins/image-fakestory.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const handler = async (m, { conn, args }) => { 4 | if (args.length < 2 && !(m.quoted && m.quoted.text)) { 5 | throw `Gunakan format: .fakestory |\n\nContoh:\n.fakestory Ryzumi|Hello World ✨✨✨` 6 | } 7 | 8 | let [username, caption] = args.join(" ").split("|") 9 | if (!caption && m.quoted && m.quoted.text) { 10 | caption = m.quoted.text 11 | } 12 | if (!username) username = await conn.getName(m.sender) 13 | 14 | const pp = await conn.profilePictureUrl(m.sender, 'image').catch(_ => './src/avatar_contact.png') 15 | 16 | const url = `${APIs.ryzumi}/api/image/fake-story?` + 17 | `username=${encodeURIComponent(username.trim())}` + 18 | `&caption=${encodeURIComponent(caption.trim())}` + 19 | `&avatar=${encodeURIComponent(pp)}` 20 | 21 | const response = await axios.get(url, { responseType: 'arraybuffer' }) 22 | const buffer = Buffer.from(response.data) 23 | 24 | await conn.sendFile(m.chat, buffer, 'fake_story.png', '', m) 25 | } 26 | 27 | handler.help = ['fakestory'] 28 | handler.tags = ['maker'] 29 | handler.command = /^(fakestory)$/i 30 | 31 | handler.register = true 32 | 33 | export default handler 34 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path, { dirname } from 'path'; 3 | import assert from 'assert'; 4 | import syntaxError from 'syntax-error'; 5 | import { fileURLToPath } from 'url'; 6 | import { createRequire } from 'module'; 7 | 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = dirname(__filename); 10 | const require = createRequire(__dirname); 11 | const folders = ['.', ...Object.keys(require(path.join(__dirname, './package.json')).directories)]; 12 | const files = []; 13 | 14 | folders.forEach(folder => { 15 | try { 16 | const jsFiles = fs.readdirSync(folder).filter(v => v.endsWith('.js')).map(file => path.resolve(folder, file)); 17 | files.push(...jsFiles); 18 | } catch (err) { 19 | console.error(`Error reading folder ${folder}:`, err); 20 | } 21 | }); 22 | 23 | files.forEach(file => { 24 | if (file !== __filename) { 25 | console.error('Checking', file); 26 | const error = syntaxError(fs.readFileSync(file, 'utf8'), file, { 27 | sourceType: 'module', 28 | allowReturnOutsideFunction: true, 29 | allowAwaitOutsideFunction: true 30 | }); 31 | assert.ifError(error); 32 | console.log('Done ☑️', file); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /plugins/group-hidetag.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text, participants }) => { 2 | const fallbackText = ( 3 | m.quoted?.text || 4 | m.quoted?.caption || 5 | m.quoted?.message?.extendedTextMessage?.text || 6 | m.quoted?.message?.conversation || 7 | '' 8 | ).trim() 9 | const msgText = (text || '').trim() || fallbackText 10 | if (!msgText) throw 'Masukkan teks setelah perintah atau balas pesan berteks lalu ketik .hidetag' 11 | 12 | const fkontak = { 13 | "key": { 14 | "participants": "0@s.whatsapp.net", 15 | "remoteJid": "status@broadcast", 16 | "fromMe": false, 17 | "id": "Halo" 18 | }, 19 | "message": { 20 | "contactMessage": { 21 | "vcard": `BEGIN:VCARD\nVERSION:3.0\nN:Sy;Bot;;;\nFN:y\nitem1.TEL;waid=${m.sender.split('@')[0]}:${m.sender.split('@')[0]}\nitem1.X-ABLabel:Ponsel\nEND:VCARD` 22 | } 23 | }, 24 | "participant": "0@s.whatsapp.net" 25 | } 26 | 27 | await conn.sendMessage( 28 | m.chat, 29 | { text: msgText, mentions: participants.map(a => a.id) }, 30 | { quoted: fkontak } 31 | ) 32 | } 33 | 34 | handler.help = ['hidetag'] 35 | handler.tags = ['group'] 36 | handler.command = /^(hidetag)$/i 37 | 38 | handler.group = true 39 | handler.admin = true 40 | 41 | export default handler 42 | -------------------------------------------------------------------------------- /plugins/internet-lyrics.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, text, usedPrefix, command }) => { 4 | if (!text) throw `Contoh\n*${usedPrefix}${command} Seven oops - Orange*`; 5 | 6 | 7 | await m.react('🕓') 8 | 9 | try { 10 | const response = await axios.get(`${APIs.ryzumi}/api/search/lyrics?query=${encodeURIComponent(text)}`); 11 | const results = response.data; 12 | 13 | if (results && results.length > 0) { 14 | const firstResult = results[0]; 15 | 16 | m.reply(` 17 | *Title:* ${firstResult.name} 18 | *Artist:* ${firstResult.artistName} 19 | *Album:* ${firstResult.albumName} 20 | *Duration:* ${Math.floor(firstResult.duration / 60)}:${(firstResult.duration % 60).toString().padStart(2, '0')} 21 | 22 | *Lyrics:* 23 | ${firstResult.plainLyrics} 24 | `.trim()); 25 | } else { 26 | throw new Error('Lirik tidak ditemukan'); 27 | } 28 | } catch (error) { 29 | conn.reply(m.chat, `Terjadi kesalahan saat memproses permintaan. ${error.message}`, m); 30 | } 31 | }; 32 | 33 | handler.help = ['lirik'].map(v => v + ' '); 34 | handler.tags = ['internet']; 35 | handler.command = /^(lirik|lyrics|lyric)$/i; 36 | 37 | handler.register = true 38 | 39 | export default handler 40 | -------------------------------------------------------------------------------- /plugins/ai-negrosiasi.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | let handler = async (m, { conn }) => { 5 | 6 | await m.react('🕓') 7 | 8 | try { 9 | let q = m.quoted ? m.quoted : m 10 | let mime = (q.msg || q).mimetype || '' 11 | if (!mime) throw 'Kirim/Reply Gambar dengan cmd .hitamkan' 12 | 13 | let media = await q.download() 14 | if (!media) throw 'Gagal mendownload media!' 15 | 16 | let cdnResult = await ryzenCDN(media) 17 | if (!cdnResult || !cdnResult.url) { 18 | throw 'Gagal upload ke RyzenCDN!' 19 | } 20 | let url = cdnResult.url 21 | 22 | let response = await axios.get(`${APIs.ryzumi}/api/ai/hitamkan`, { 23 | params: { 24 | imageUrl: url 25 | }, 26 | responseType: 'arraybuffer' 27 | }) 28 | 29 | await conn.sendFile(m.chat, response.data, '', global.wm, m) 30 | 31 | } catch (error) { 32 | m.reply(error.message || 'Internal server error') 33 | console.error(error) 34 | } 35 | } 36 | 37 | handler.help = ['hitamkan'] 38 | handler.tags = ['ai'] 39 | handler.command = /^(hitamkan)$/i 40 | handler.register = true 41 | handler.limit = 2 42 | 43 | export default handler 44 | -------------------------------------------------------------------------------- /plugins/info-sholat.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | let handler = async (m, { text }) => { 4 | if (!text) throw 'Masukan nama kotanya' 5 | let res = await jadwalsholat(text) 6 | res = res.map(({ lokasi, daerah, jadwal }) => { 7 | delete jadwal.tanggal, delete jadwal.date 8 | jadwal = Object.keys(jadwal).map((v) => `• ${v.capitalize()}: ${jadwal[v]}`).join('\n') 9 | return `*Lokasi:* ${lokasi}\n*Daerah:* ${daerah}\n*Jadwal:*\n${jadwal}` 10 | }).join`\n\n` 11 | m.reply(res) 12 | } 13 | handler.help = ['sholat'] 14 | handler.tags = ['info'] 15 | handler.command = /^(jadwalsholat|sholat)$/i 16 | 17 | export default handler 18 | 19 | async function jadwalsholat(query) { 20 | let id = await (await fetch(`https://api.myquran.com/v2/sholat/kota/cari/${query}`)).json() 21 | if (id.status !== true) throw id.message 22 | id = id.data 23 | let result = [], d = new Date().toLocaleDateString('id', { timeZone: 'Asia/Jakarta' }).split('/') 24 | for (let i = 0; i < id.length; i++) { 25 | let res = await fetch(`https://api.myquran.com/v2/sholat/jadwal/${id[i].id}/${d[2]}/${d[1]}/${d[0]}`) 26 | res = await res.json() 27 | result.push({ lokasi: res.data.lokasi, daerah: res.data.daerah, jadwal: res.data.jadwal }) 28 | } 29 | return result 30 | } -------------------------------------------------------------------------------- /plugins/_afk.js: -------------------------------------------------------------------------------- 1 | let handler = (m) => m; 2 | handler.before = (m) => { 3 | let user = global.db.data.users[m.sender]; 4 | if (user.afk > -1) { 5 | m.reply( 6 | ` 7 | Kamu berhenti AFK${user.afkReason ? " setelah " + user.afkReason : ""} 8 | Selama ${clockString(new Date() - user.afk)} 9 | `.trim() 10 | ); 11 | user.afk = -1; 12 | user.afkReason = ""; 13 | } 14 | let jids = [ 15 | ...new Set([ 16 | ...(m.mentionedJid || []), 17 | ...(m.quoted ? [m.quoted.sender] : []), 18 | ]), 19 | ]; 20 | for (let jid of jids) { 21 | let user = global.db.data.users[jid]; 22 | if (!user) continue; 23 | let afkTime = user.afk; 24 | if (!afkTime || afkTime < 0) continue; 25 | let reason = user.afkReason || ""; 26 | m.reply( 27 | ` 28 | Jangan tag dia! 29 | Dia sedang AFK ${reason ? "dengan alasan " + reason : "tanpa alasan"} 30 | Selama ${clockString(new Date() - afkTime)} 31 | `.trim() 32 | ); 33 | } 34 | return true; 35 | }; 36 | 37 | export default handler; 38 | 39 | function clockString(ms) { 40 | let h = isNaN(ms) ? "--" : Math.floor(ms / 3600000); 41 | let m = isNaN(ms) ? "--" : Math.floor(ms / 60000) % 60; 42 | let s = isNaN(ms) ? "--" : Math.floor(ms / 1000) % 60; 43 | return [h, m, s].map((v) => v.toString().padStart(2, 0)).join(":"); 44 | } 45 | -------------------------------------------------------------------------------- /plugins/anime-info.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | var handler = async (m, { conn, text }) => { 4 | if (!text) throw `*Masukan Judul Anime Yang Ingin Kamu Cari !*`; 5 | 6 | let res = await fetch('https://api.jikan.moe/v4/anime?q=' + text); 7 | 8 | if (!res.ok) throw 'Tidak Ditemukan'; 9 | 10 | let json = await res.json(); 11 | let animeData = json.data[0]; 12 | 13 | if (!animeData) throw 'Anime tidak ditemukan.'; 14 | 15 | let { 16 | title_japanese, 17 | url, 18 | type, 19 | score, 20 | members, 21 | status, 22 | synopsis, 23 | favorites, 24 | images, 25 | genres, 26 | } = animeData; 27 | 28 | let genreList = genres.map((genre) => genre.name).join(', '); 29 | 30 | let animeingfo = ` 31 | Title: ${title_japanese} 32 | Type: ${type} 33 | Genres: ${genreList} 34 | Score: ${score} 35 | Members: ${members} 36 | Status: ${status} 37 | Favorites: ${favorites} 38 | URL: ${url} 39 | Synopsis: ${synopsis} 40 | `; 41 | 42 | conn.sendFile(m.chat, images.jpg.image_url, 'anjime.jpg', `*ANIME INFO*\n` + animeingfo, m); 43 | }; 44 | 45 | handler.help = ['animeinfo ']; 46 | handler.tags = ['anime']; 47 | handler.command = /^(animeinfo)$/i; 48 | 49 | handler.register = true 50 | 51 | export default handler 52 | -------------------------------------------------------------------------------- /plugins/ai-faceswap.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | let handler = async (m, { conn, args }) => { 5 | try { 6 | await m.react('🕓') 7 | if (!args[0]) throw 'Masukkan link gambar original' 8 | let q = m.quoted ? m.quoted : m 9 | let mime = (q.msg || q).mimetype || '' 10 | if (!mime) throw 'Kirim/Reply Gambar dengan caption .faceswap' 11 | let media = await q.download() 12 | if (!media) throw 'Gagal mendownload media!' 13 | let cdnResult = await ryzenCDN(media) 14 | let url = cdnResult.url || cdnResult 15 | if (!url) throw 'Gagal upload ke RyzenCDN!' 16 | 17 | 18 | let response = await axios.get(`${APIs.ryzumi}/api/ai/faceswap`, { 19 | params: { 20 | original: args[0], 21 | face: url 22 | }, 23 | responseType: 'arraybuffer' 24 | }) 25 | 26 | await conn.sendFile(m.chat, response.data, '', global.wm, m) 27 | } catch (error) { 28 | m.reply(error.message || 'Internal server error') 29 | console.error(error) 30 | } 31 | } 32 | 33 | handler.help = ['faceswap'] 34 | handler.tags = ['ai'] 35 | handler.command = /^(faceswap)$/i 36 | handler.register = true 37 | handler.limit = 5 38 | 39 | export default handler 40 | -------------------------------------------------------------------------------- /plugins/group-kick.js: -------------------------------------------------------------------------------- 1 | import { areJidsSameUser } from '@whiskeysockets/baileys' 2 | 3 | var handler = async (m, { conn, text, participants }) => { 4 | const rawWho = m.quoted?.sender || (m.mentionedJid && m.mentionedJid[0]) || (text ? (text.replace(/\D/g, '') + '@s.whatsapp.net') : '') 5 | if (!rawWho) throw 'Reply / tag yang ingin di kick' 6 | 7 | const who = typeof conn.getJid === 'function' ? conn.getJid(rawWho) : (rawWho.decodeJid ? rawWho.decodeJid() : rawWho) 8 | 9 | if (areJidsSameUser(who, m.sender)) throw 'Reply / tag yang ingin di kick' 10 | 11 | const parts = participants 12 | .map(p => p?.id || p?.jid || p?.participant || p?.lid) 13 | .filter(Boolean) 14 | .map(raw => ({ raw, norm: (typeof conn.getJid === 'function' ? conn.getJid(raw) : (raw.decodeJid ? raw.decodeJid() : raw)) })) 15 | 16 | const matched = parts.find(p => areJidsSameUser(p.norm, who)) 17 | if (!matched) throw `Target tidak berada dalam Grup !` 18 | 19 | await conn.groupParticipantsUpdate(m.chat, [matched.raw], 'remove') 20 | m.reply(`Success`) 21 | } 22 | 23 | handler.help = ['kick'].map(v => v + ' @user') 24 | handler.tags = ['group'] 25 | handler.command = /^(kick)$/i 26 | 27 | handler.owner = false 28 | handler.group = true 29 | handler.botAdmin = true 30 | handler.admin = true 31 | 32 | export default handler -------------------------------------------------------------------------------- /plugins/owner-cleartmp.js: -------------------------------------------------------------------------------- 1 | import { tmpdir } from 'os' 2 | import { readdirSync, statSync, unlinkSync, existsSync } from 'fs' 3 | 4 | let handler = async (m, { conn, usedPrefix: _p, __dirname, args }) => { 5 | 6 | const tmp = [tmpdir(), join(__dirname, '../tmp')]; 7 | const filenames = []; 8 | 9 | tmp.forEach(dirname => { 10 | readdirSync(dirname).forEach(file => { 11 | filenames.push(join(dirname, file)); 12 | }); 13 | }); 14 | 15 | const deletedFiles = []; 16 | 17 | filenames.forEach(file => { 18 | const stats = statSync(file); 19 | 20 | if (stats.isDirectory()) { 21 | // console.log(`Skipping directory: ${file}`); 22 | } else { 23 | unlinkSync(file); 24 | deletedFiles.push(file); 25 | } 26 | }); 27 | 28 | conn.reply(m.chat, 'Success!', m); 29 | 30 | if (deletedFiles.length > 0) { 31 | // console.log('Deleted files:', deletedFiles); 32 | // conn.reply(m.chat, `Deleted files:\n${deletedFiles.join('\n')}`, m); 33 | conn.reply(m.chat, `Files deleted`, m) 34 | } 35 | 36 | if (deletedFiles.length == 0) { 37 | conn.reply(m.chat, 'Tidak ada file yang tersisa di tmp', m); 38 | } 39 | } 40 | 41 | handler.help = ['cleartmp'] 42 | handler.tags = ['owner'] 43 | handler.command = /^(cleartmp|clear|tmpclear|cleantmp)$/i 44 | handler.rowner = true 45 | 46 | export default handler -------------------------------------------------------------------------------- /plugins/sticker-sticker.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, args, text }) => { 2 | const q = m.quoted ? m.quoted : m; 3 | const mime = (q.msg || q).mimetype || ''; 4 | 5 | // Early validation: ensure we actually have a media message structure 6 | if (!q.mediaType || !/image|video|webp/.test(mime)) { 7 | return m.reply('Reply (balas) gambar, video, atau stiker dengan perintah .s untuk membuat stiker.'); 8 | } 9 | 10 | // Treat GIFs as videos (WhatsApp sends them as mp4); guard for duration 11 | const isVideoLike = /video|gif/.test(mime) || (q.mediaType === 'videoMessage'); 12 | const seconds = Number(q.msg?.seconds || q.seconds || q.duration || 0); 13 | if (isVideoLike && seconds > 10) { 14 | return m.reply('Video harus berdurasi di bawah 10 detik.'); 15 | } 16 | 17 | let media; 18 | try { 19 | media = await q.download(); 20 | } catch (e) { 21 | return m.reply('Gagal mengambil media: ' + e.message); 22 | } 23 | 24 | let exif; 25 | if (text) { 26 | const [packname, author] = text.split(/[,|\-+&]/); 27 | exif = { packName: packname?.trim() || '', packPublish: author?.trim() || '' }; 28 | } 29 | return conn.sendSticker(m.chat, media, m, exif); 30 | }; 31 | 32 | handler.help = ['maker'] 33 | handler.tags = ['maker'] 34 | handler.command = /^s(tic?ker)?(gif)?$/i 35 | handler.register = true 36 | 37 | export default handler -------------------------------------------------------------------------------- /plugins/stalk-twitter.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | if (!text || !text.trim()) throw 'Masukkan username yang valid!' 5 | let username = text.trim() 6 | 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | let { data } = await axios.get(`${APIs.ryzumi}/api/stalk/twitter?username=${username}`) 12 | if (data.message !== 'OK') throw data.message || 'Terjadi kesalahan saat mengambil data!' 13 | 14 | let user = data.user 15 | let caption = ` 16 | ID: ${user.id} 17 | URL: ${user.url} 18 | Screen Name: ${user.screen_name} 19 | Name: ${user.name} 20 | Location: ${user.location} 21 | Description: ${user.description} 22 | Followers: ${user.followers} 23 | Following: ${user.following} 24 | Likes: ${user.likes} 25 | Banner URL: ${user.banner_url} 26 | Avatar URL: ${user.avatar_url} 27 | Joined At: ${user.joined_at} 28 | Website: ${user.website ? user.website : '-'} 29 | `.trim() 30 | 31 | await conn.sendMessage(m.chat, { image: { url: user.avatar_url }, caption }, { quoted: m }) 32 | } catch (err) { 33 | m.reply('Error:' + err.message) 34 | } 35 | } 36 | 37 | handler.help = ['twitterstalk'] 38 | handler.tags = ['stalk'] 39 | handler.command = /^(twitterstalk|xstalk)$/i 40 | 41 | handler.register = true 42 | handler.limit = true 43 | 44 | export default handler 45 | -------------------------------------------------------------------------------- /plugins/owner-clearsession.js: -------------------------------------------------------------------------------- 1 | import { join } from 'path' 2 | import { readdirSync, statSync, unlinkSync } from 'fs' 3 | 4 | let handler = async (m, { conn, usedPrefix: _p, __dirname, args }) => { 5 | 6 | const sessionsDir = join(__dirname, '../sessions') 7 | const filenames = [] 8 | 9 | readdirSync(sessionsDir).forEach(file => { 10 | if (file !== 'creds.json') { 11 | filenames.push(join(sessionsDir, file)) 12 | } 13 | }) 14 | 15 | const deletedFiles = [] 16 | 17 | filenames.forEach(file => { 18 | const stats = statSync(file) 19 | if (stats.isDirectory()) { 20 | // console.log(`Skipping directory: ${file}`) 21 | } else { 22 | unlinkSync(file) 23 | deletedFiles.push(file) 24 | } 25 | }) 26 | 27 | conn.reply(m.chat, 'Success!', m) 28 | 29 | if (deletedFiles.length > 0) { 30 | // console.log('Deleted files:', deletedFiles) 31 | // conn.reply(m.chat, `Deleted files:\n${deletedFiles.join('\n')}`, m) 32 | conn.reply(m.chat, `Files deleted`, m) 33 | } else { 34 | conn.reply(m.chat, 'Tidak ada file yang tersisa di sessions', m) 35 | } 36 | } 37 | 38 | handler.help = ['clearsession'] 39 | handler.tags = ['owner'] 40 | handler.command = /^(clearsession|clear)$/i 41 | handler.rowner = true 42 | 43 | export default handler 44 | -------------------------------------------------------------------------------- /plugins/ai-waifu2x.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | let handler = async (m, { conn, usedPrefix, command, text }) => { 5 | try { 6 | await m.react('🕓') 7 | let who = m.mentionedJid && m.mentionedJid[0] ? m.mentionedJid[0] : m.fromMe ? conn.user.jid : m.sender 8 | let name = await conn.getName(who) 9 | let q = m.quoted ? m.quoted : m 10 | let mime = (q.msg || q).mimetype || '' 11 | if (!mime) throw 'Kirim/Reply Gambar dengan caption .waifu2x' 12 | 13 | let media = await q.download() 14 | let url = await uploadPomf(media) 15 | 16 | // Mengirim permintaan ke API waifu2x dan mendapatkan buffer 17 | let response = await fetch(`${APIs.ryzumi}/api/ai/waifu2x?url=${url}`) 18 | if (!response.ok) throw new Error('Gagal menghubungi API waifu2x') 19 | 20 | let hasil = Buffer.from(await response.arrayBuffer()) 21 | 22 | // Mengirim file buffer langsung ke chat 23 | await conn.sendFile(m.chat, hasil, 'hasil.jpg', global.wm, m) 24 | } catch (error) { 25 | console.error(error) 26 | m.reply('Internal server error') 27 | } 28 | } 29 | 30 | handler.help = ['waifu2x'] 31 | handler.tags = ['ai'] 32 | handler.command = /^(waifu2x)$/i 33 | 34 | handler.register = true 35 | handler.limit = 15 36 | 37 | export default handler 38 | -------------------------------------------------------------------------------- /plugins/ai-gemini-image.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | let handler = async (m, { conn, text }) => { 5 | 6 | await m.react('🕓') 7 | 8 | try { 9 | if (!text) throw 'Masukkan text!' 10 | 11 | let q = m.quoted ? m.quoted : m 12 | let mime = (q.msg || q).mimetype || '' 13 | if (!mime) throw 'Kirim/Reply Gambar dengan caption .geminiimage' 14 | 15 | let media = await q.download() 16 | if (!media) throw 'Gagal mendownload media!' 17 | 18 | let cdnResult = await ryzenCDN(media) 19 | if (!cdnResult || !cdnResult.url) { 20 | throw 'Gagal upload ke RyzenCDN!' 21 | } 22 | let url = cdnResult.url 23 | 24 | let response = await axios.get(`${APIs.ryzumi}/api/ai/image/gemini`, { 25 | params: { 26 | text: text, 27 | url: url 28 | }, 29 | responseType: 'arraybuffer' 30 | }) 31 | 32 | await conn.sendFile(m.chat, response.data, '', global.wm, m) 33 | 34 | } catch (error) { 35 | m.reply(error.message || 'Internal server error') 36 | console.error(error) 37 | } 38 | } 39 | 40 | handler.help = ['geminiedit'] 41 | handler.tags = ['ai'] 42 | handler.command = /^(geminiedit)$/i 43 | handler.register = true 44 | handler.limit = 2 45 | 46 | export default handler 47 | -------------------------------------------------------------------------------- /plugins/image-gimage.js: -------------------------------------------------------------------------------- 1 | const fetch = globalThis.fetch ?? (await import('node-fetch')).default; 2 | 3 | var handler = async (m, { conn, text, usedPrefix, command }) => { 4 | if (!text) throw `Contoh: ${usedPrefix}${command} Minecraft`; 5 | 6 | try { 7 | const url = `${APIs.ryzumi}/api/search/gimage?query=${encodeURIComponent(text)}`; 8 | const res = await fetch(url, { method: 'GET', headers: { accept: 'application/json' } }); 9 | 10 | if (!res.ok) throw new Error(`HTTP ${res.status}`); 11 | 12 | const data = await res.json(); 13 | if (!Array.isArray(data) || data.length === 0) { 14 | return conn.reply(m.chat, 'Maaf, nggak ada hasil untuk pencarian itu.', m); 15 | } 16 | 17 | const pick = data[Math.floor(Math.random() * data.length)]; 18 | const link = pick.image || pick.url; 19 | 20 | await conn.sendFile( 21 | m.chat, 22 | link, 23 | 'google.jpg', 24 | `*${htki} Google Image ${htka}*\n🔎 *Result:* ${text}\n🌎 *Source:* Google\n`, 25 | m 26 | ); 27 | } catch (e) { 28 | console.error(e); 29 | conn.reply(m.chat, 'Lagi ada gangguan saat ambil gambar. Coba ulangi ya, Sayang~', m); 30 | } 31 | }; 32 | 33 | handler.help = ['gimage ', 'image ']; 34 | handler.tags = ['internet']; 35 | handler.command = /^(gimage|image)$/i; 36 | 37 | handler.register = true 38 | handler.limit = true 39 | 40 | export default handler 41 | -------------------------------------------------------------------------------- /lib/uploadFile.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import FormData from 'form-data'; 3 | import { fileTypeFromBuffer } from 'file-type'; 4 | 5 | const ryzenCDN = async (inp) => { 6 | try { 7 | const form = new FormData(); 8 | const files = Array.isArray(inp) ? inp : [inp]; 9 | 10 | for (const file of files) { 11 | const buffer = Buffer.isBuffer(file) ? file : file.buffer; 12 | if (!Buffer.isBuffer(buffer)) throw new Error('Invalid buffer format'); 13 | 14 | const type = await fileTypeFromBuffer(buffer); 15 | if (!type) throw new Error('Unsupported file type'); 16 | 17 | const originalName = (file.originalname || 'file').split('.').shift(); 18 | 19 | form.append('file', buffer, { 20 | filename: `${originalName}.${type.ext}`, 21 | contentType: type.mime 22 | }); 23 | } 24 | 25 | const res = await fetch(`${APIs.ryzumi}/api/uploader/ryzencdn`, { 26 | method: 'POST', 27 | headers: { 28 | 'accept': 'application/json', 29 | ...form.getHeaders(), 30 | }, 31 | body: form, 32 | }); 33 | 34 | const json = await res.json(); 35 | if (!json.success) throw new Error(json.message || 'Upload failed'); 36 | 37 | return Array.isArray(inp) ? json.map(f => f.url) : json; 38 | 39 | } catch (error) { 40 | throw new Error(`RyzenCDN Error: ${error.message}`); 41 | } 42 | }; 43 | 44 | export { ryzenCDN }; -------------------------------------------------------------------------------- /plugins/tool-cekpln.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args }) => { 4 | const id = args[0] 5 | 6 | if (!id) throw 'Masukkan ID Pelanggan PLN Pascabayar\nContoh: `.cekpln 1234567890`' 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | let res = await axios.get(`${APIs.ryzumi}/api/tool/cek-pln?id=${id}`) 12 | let result = res.data 13 | 14 | if (!result.success || !result.result) throw 'API tidak mengembalikan data yang valid' 15 | 16 | const data = result.result 17 | let ini_text = ` 18 | 🔌 *HASIL CEK PLN PASCABAYAR* 19 | 20 | ID Pelanggan : ${data.customer_id} 21 | Nama : ${data.customer_name} 22 | Daya : ${data.power_category} 23 | Periode : ${data.billing_period} 24 | Meteran : ${data.meter_reading} 25 | Tagihan : ${data.outstanding_balance} 26 | Jumlah Tagihan : ${data.total_bills} bulan 27 | `.trim() 28 | 29 | await conn.sendMessage(m.chat, { 30 | text: ini_text, 31 | }); 32 | 33 | } catch (e) { 34 | await conn.sendMessage(m.chat, { 35 | text: `Gagal mengambil data PLN:\n${e}`, 36 | }); 37 | } 38 | } 39 | 40 | handler.help = ['cekpln '] 41 | handler.tags = ['tool'] 42 | handler.command = /^(pln|cekpln)$/i 43 | 44 | handler.register = true 45 | handler.limit = false 46 | 47 | export default handler 48 | -------------------------------------------------------------------------------- /plugins/sticker-telegram.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | 3 | let handler = async (m, { conn, args, usedPrefix, command }) => { 4 | if (!args[0]) throw `Contoh:\n${usedPrefix + command} https://t.me/addstickers/sshaaaaa` 5 | if (!args[0].match(/(https:\/\/t.me\/addstickers\/)/gi)) throw `URL-nya gak valid, Sayang~` 6 | 7 | let apiUrl = `${APIs.ryzumi}/api/image/sticker-tele?url=${encodeURIComponent(args[0])}` 8 | let res = await fetch(apiUrl) 9 | if (!res.ok) throw `Err: ${res.status}` 10 | 11 | let json = await res.json() 12 | let stickers = json.stickers?.stickers || [] 13 | if (!stickers.length) throw `Sticker not found` 14 | 15 | m.reply(`*Total stiker:* ${stickers.length}`) 16 | 17 | for (let s of stickers) { 18 | if (!s.is_animated && s.image_url) { 19 | try { 20 | let imgRes = await fetch(s.image_url) 21 | conn.sendSticker(m.chat, imgRes, m) 22 | await delay(5000) 23 | } catch (e) { 24 | console.error(`Gagal proses stiker: ${e}`) 25 | } 26 | } 27 | } 28 | 29 | throw `*Done*` 30 | } 31 | 32 | handler.help = ['stickertele'] 33 | handler.tags = ['maker'] 34 | handler.command = /^(stic?kertele(gram)?)$/i 35 | handler.limit = 15 36 | handler.register = true 37 | 38 | export default handler 39 | 40 | const delay = time => new Promise(res => setTimeout(res, time)) 41 | -------------------------------------------------------------------------------- /plugins/tool-tts.js: -------------------------------------------------------------------------------- 1 | import gtts from 'node-gtts' 2 | import { readFileSync, unlinkSync } from 'fs' 3 | import { join } from 'path' 4 | 5 | const defaultLang = 'id' 6 | let handler = async (m, { conn, args, usedPrefix, command }) => { 7 | 8 | let lang = args[0] 9 | let text = args.slice(1).join(' ') 10 | if ((args[0] || '').length !== 2) { 11 | lang = defaultLang 12 | text = args.join(' ') 13 | } 14 | if (!text && m.quoted?.text) text = m.quoted.text 15 | 16 | let res 17 | try { res = await tts(text, lang) } 18 | catch (e) { 19 | m.reply(e + '') 20 | text = args.join(' ') 21 | if (!text) throw `Use example ${usedPrefix}${command} en hello world` 22 | res = await tts(text, defaultLang) 23 | } finally { 24 | if (res) conn.sendFile(m.chat, res, 'tts.opus', null, m, true) 25 | } 26 | } 27 | handler.help = ['tts '] 28 | handler.tags = ['tools'] 29 | handler.command = /^g?tts$/i 30 | 31 | handler.register = true 32 | 33 | export default handler 34 | 35 | function tts(text, lang = 'id') { 36 | console.log(lang, text) 37 | return new Promise((resolve, reject) => { 38 | try { 39 | let tts = gtts(lang) 40 | let filePath = join(global.__dirname(import.meta.url), '../tmp', (1 * new Date) + '.wav') 41 | tts.save(filePath, text, () => { 42 | resolve(readFileSync(filePath)) 43 | unlinkSync(filePath) 44 | }) 45 | } catch (e) { reject(e) } 46 | }) 47 | } -------------------------------------------------------------------------------- /plugins/downloader-slideshare.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | const handler = async (m, { conn, args, command, usedPrefix }) => { 4 | if (args.length < 1) throw `> Silakan berikan URL SlideShare\n\nContoh: \n*${usedPrefix + command} LINKNYA*\n*${usedPrefix + command} https://www.slideshare.net/StevanyStevany/materi-lengkap-tentang-power-point*` 5 | 6 | const url = args[0]; 7 | const filetypes = ['pdf', 'pptx']; 8 | 9 | 10 | await m.react('🕓') 11 | 12 | try { 13 | for (const filetype of filetypes) { 14 | const response_get = await fetch(`https://bioskop-six.vercel.app/slideshare?url=${encodeURIComponent(url)}&filetype=${filetype}`); 15 | const { download_url } = await response_get.json(); 16 | 17 | conn.sendFile(m.chat, download_url, `${url.split('/').pop()}.${filetype}`, `> File ${filetype.toUpperCase()} berhasil diunduh dan disimpan sebagai ${url.split('/').pop()}.${filetype}`, m); 18 | } 19 | } catch (error) { 20 | console.error("Error:", error); 21 | conn.reply(m.chat, `> Terjadi kesalahan: ${error.message}\n\nSilakan berikan URL SlideShare\nContoh: \n *${usedPrefix + command} LINKNYA*`, m); 22 | } 23 | }; 24 | 25 | handler.command = /^(slideshare|slidedl|slidesharedl|slidedownload)$/i 26 | handler.help = ['slideshare '] 27 | handler.tags = ['downloader'] 28 | handler.register = true 29 | handler.limit = true 30 | 31 | export default handler -------------------------------------------------------------------------------- /plugins/internet-ghsearch.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | let handler = async (m, { text, command, usedPrefix }) => { 3 | if (!text) throw 'Cari apa?' 4 | let res = await fetch(global.API('https://api.github.com', '/search/repositories', { 5 | q: text 6 | })) 7 | let json = await res.json() 8 | if (res.status !== 200) throw json 9 | let str = json.items.map((repo, index) => { 10 | return ` 11 | ${1 + index}. *${repo.full_name}*${repo.fork ? ' (fork)' : ''} 12 | _${repo.html_url}_ 13 | _Dibuat pada *${formatDate(repo.created_at)}*_ 14 | _Terakhir update pada *${formatDate(repo.updated_at)}*_ 15 | 👁 ${repo.watchers} 🍴 ${repo.forks} ⭐ ${repo.stargazers_count} 16 | ${repo.open_issues} Issue${repo.description ? ` 17 | *Deskripsi:*\n${repo.description}` : ''} 18 | *Clone:* \`\`\`$ git clone ${repo.clone_url}\`\`\` 19 | `.trim() 20 | }).join('\n\n') 21 | m.reply(str) 22 | } 23 | handler.help = ['githubsearch'].map(v => v + ' ') 24 | handler.tags = ['internet'] 25 | 26 | handler.register = true 27 | handler.command = /^g(ithub|h)s(earch)?$/i 28 | 29 | export default handler 30 | 31 | function formatDate(n, locale = 'id') { 32 | let d = new Date(n) 33 | return d.toLocaleDateString(locale, { 34 | weekday: 'long', 35 | day: 'numeric', 36 | month: 'long', 37 | year: 'numeric', 38 | hour: 'numeric', 39 | minute: 'numeric', 40 | second: 'numeric' 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /plugins/tool-spamwa.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | let [nomor, pesan, jumlah] = text.split('|') 3 | if (!nomor) throw '- Format: *#spamwa nomor|teks|jumlah*\n- Contoh: *.spamwa 62895619519333|Apa coba|50*' 4 | if (!pesan) throw '- Format: *#spamwa nomor|teks|jumlah*\n- Contoh: *.spamwa 62895619519333|Apa coba|50*' 5 | if (jumlah && isNaN(jumlah)) throw '- Format: *.spamwa nomor|teks|jumlah*\n- Contoh: *.spamwa 62895619519333|Apa coba|50*' 6 | 7 | let fixedNumber = nomor.replace(/[-+<>@]/g, '').replace(/ +/g, '').replace(/^[0]/g, '62') + '@s.whatsapp.net' 8 | let fixedJumlah = jumlah ? jumlah * 1 : 10 9 | if (fixedJumlah > 50) throw '*Maks 50 Pesan*' 10 | 11 | await m.reply(`*Spam Success To That Number*\nEstimated Sent All *${fixedJumlah}*`) 12 | 13 | for (let i = 0; i < fixedJumlah; i++) { 14 | let teks = `${pesan.trim()}\n\n[${i + 1}/${fixedJumlah}]`; // Tambahkan informasi iterasi dalam pesan 15 | await conn.relayMessage(fixedNumber, { 16 | text: teks, 17 | extendedTextMessage: { 18 | text: teks, 19 | }, 20 | }, {}) 21 | } 22 | } 23 | 24 | handler.help = ['spamwa ||'] 25 | handler.tags = ['tools'] 26 | handler.command = /^spam(wa)?$/i 27 | 28 | handler.register = true 29 | handler.group = false 30 | handler.owner = true 31 | handler.private = true 32 | handler.limit = 10 33 | 34 | export default handler 35 | -------------------------------------------------------------------------------- /plugins/downloader-gdrive.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args }) => { 4 | if (!(args[0] || '').match(/([\w-]){33}|([\w-]){19}/)) throw '[!] Input GoogleDrive URL' 5 | 6 | const someincludes = (data, id) => { 7 | let res = data.find(el => id.includes(el)) 8 | return res ? true : false 9 | } 10 | 11 | try { 12 | const url = `${APIs.ryzumi}/api/downloader/gdrive?url=${encodeURIComponent(args[0])}` 13 | const { data: res } = await axios.get(url) 14 | 15 | if (res.fileSize.slice(-2) == 'GB') 16 | return m.reply(`Ngotak dong.\nMana bisa ngirim video ${res.fileSize}`) 17 | if (!someincludes(['kB', 'KB'], res.fileSize.slice(-2)) && parseInt(res.fileSize) > 500) 18 | return m.reply(`Filesize: ${res.fileSize}\nTidak dapat mengirim, maksimal file 500 MB`) 19 | 20 | let txt = `*[ Downloading file ]*\n\n` 21 | txt += `*Name :* ${res.fileName}\n` 22 | txt += `*Size :* ${res.fileSize}\n` 23 | txt += `*Type :* ${res.mimetype}` 24 | await m.reply(txt) 25 | 26 | if (!res.downloadUrl) throw 'Download URL tidak tersedia' 27 | await conn.sendFile(m.chat, res.downloadUrl, res.fileName, res.fileName, m) 28 | } catch (e) { 29 | console.log(e) 30 | throw 'Bot tidak memiliki akses ke GoogleDrive ini' 31 | } 32 | } 33 | 34 | handler.help = ['gdrive'].map(v => v + ' ') 35 | handler.tags = ['downloader'] 36 | handler.command = /^(gdrive)$/i 37 | 38 | handler.limit = true 39 | handler.register = true 40 | 41 | export default handler 42 | -------------------------------------------------------------------------------- /lib/uploadImage.js: -------------------------------------------------------------------------------- 1 | import { fileTypeFromBuffer } from 'file-type'; 2 | import FormData from 'form-data'; 3 | import fetch from 'node-fetch'; 4 | 5 | /** 6 | * Upload via RyzenCDN 7 | * @param {Buffer} content File Buffer 8 | * @return {Promise} 9 | */ 10 | const uploadPomf = async (content) => { 11 | try { 12 | if (!Buffer.isBuffer(content)) throw new Error('content must be a Buffer'); 13 | 14 | const type = await fileTypeFromBuffer(content); 15 | if (!type) throw new Error('Unsupported or unknown file type'); 16 | 17 | const form = new FormData(); 18 | form.append('file', content, { 19 | filename: `upload.${type.ext}`, 20 | contentType: type.mime, 21 | }); 22 | 23 | const res = await fetch(`${APIs.ryzumi}/api/uploader/ryzencdn`, { 24 | method: 'POST', 25 | headers: { 26 | accept: 'application/json', 27 | ...form.getHeaders(), 28 | }, 29 | body: form, 30 | }); 31 | 32 | const json = await res.json(); 33 | 34 | // Common response shapes fallback 35 | if (json?.success === true && json?.data?.url) return json.data.url; 36 | if (json?.success === true && json?.url) return json.url; 37 | if (Array.isArray(json) && json[0]?.url) return json[0].url; 38 | 39 | throw new Error(json?.message || 'Upload failed'); 40 | } catch (error) { 41 | console.error('RyzenCDN upload failed:', error?.message || error); 42 | throw error; 43 | } 44 | }; 45 | 46 | export { uploadPomf }; 47 | -------------------------------------------------------------------------------- /plugins/internet-mahasiswa.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | var handler = async (m, { conn, text }) => { 4 | if (!text) throw `*_Masukkan Nama Mahasiswa/Siswa Yang Ingin Kamu Cari !_*`; 5 | 6 | conn.reply(m.chat, 'Sedang mencari orangnya... Silahkan tunggu.', m); 7 | 8 | const url = `${APIs.ryzumi}/api/search/mahasiswa?query=${encodeURIComponent(text)}`; 9 | 10 | try { 11 | let res = await axios.get(url); 12 | 13 | const data = res.data; 14 | 15 | if (!Array.isArray(data) || data.length === 0) { 16 | throw 'Tidak ditemukan data untuk nama tersebut.'; 17 | } 18 | 19 | let message = `Hasil pencarian untuk nama "${text}":\n\n`; 20 | 21 | data.forEach((mahasiswa, index) => { 22 | const nama = mahasiswa.nama || 'Tidak Diketahui'; 23 | const nim = mahasiswa.nim || 'Tidak Diketahui'; 24 | const namaPt = mahasiswa.nama_pt || 'Tidak Diketahui'; 25 | const namaProdi = mahasiswa.nama_prodi || 'Tidak Diketahui'; 26 | 27 | message += `${index + 1}. Nama: ${nama}\n NIM: ${nim}\n Perguruan Tinggi: ${namaPt}\n Program Studi: ${namaProdi}\n\n`; 28 | }); 29 | 30 | conn.reply(m.chat, message, m); 31 | } catch (error) { 32 | console.error(error); 33 | conn.reply(m.chat, `Terjadi kesalahan: ${error.message || error}`, m); 34 | } 35 | }; 36 | 37 | handler.help = ['mahasiswa ']; 38 | handler.tags = ['internet']; 39 | handler.command = /^(mahasiswa)$/i; 40 | 41 | handler.register = true 42 | 43 | export default handler 44 | -------------------------------------------------------------------------------- /plugins/tool-ocr.js: -------------------------------------------------------------------------------- 1 | import { uploadPomf } from '../lib/uploadImage.js' 2 | import ocrapi from 'ocr-space-api-wrapper' 3 | 4 | async function performOCR(url) { 5 | try { 6 | return await ocrapi.ocrSpace(url) 7 | } catch (error) { 8 | console.error(error) 9 | return null 10 | } 11 | } 12 | 13 | let handler = async (m, { conn, text, command, usedPrefix }) => { 14 | try { 15 | let q = m.quoted ? m.quoted : m 16 | let mime = (q.msg || q).mimetype || '' 17 | 18 | if (!mime) throw `Balas gambar dengan perintah ${usedPrefix}${command}` 19 | if (!/image\/(jpe?g|png)/.test(mime)) throw `Jenis ${mime} tidak didukung` 20 | 21 | let img = await q.download() 22 | let url = await uploadPomf(img) 23 | 24 | await m.react('🕓') 25 | 26 | let maxRetries = 99 27 | let retryCount = 0 28 | let hasil 29 | 30 | do { 31 | hasil = await performOCR(url) 32 | retryCount++ 33 | } while (!hasil && retryCount < maxRetries) 34 | 35 | if (hasil && hasil.ParsedResults && hasil.ParsedResults.length > 0) { 36 | let parsedText = hasil.ParsedResults[0].ParsedText; 37 | await m.reply(`${parsedText}`); 38 | } else { 39 | throw 'Tidak dapat menemukan teks dalam gambar' 40 | } 41 | } catch (error) { 42 | console.error(error) 43 | m.reply(`Balas gambar dengan perintah ${usedPrefix}${command}`) 44 | } 45 | } 46 | 47 | handler.help = ['ocr'] 48 | handler.tags = ['tools'] 49 | handler.command = /^(ocr)$/i 50 | 51 | export default handler -------------------------------------------------------------------------------- /plugins/tool-chord.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | function decodeHtml(html) { 4 | const entities = { 5 | '"': '"', 6 | ''': "'", 7 | '<': '<', 8 | '>': '>', 9 | '&': '&', 10 | '–': '–', 11 | '—': '—', 12 | ' ': ' ' 13 | }; 14 | 15 | return html.replace(/&[a-zA-Z0-9#]+;/g, (match) => entities[match] || match); 16 | } 17 | 18 | let handler = async (m, { text }) => { 19 | if (!text) throw 'Input Query'; 20 | let a = await chord(text); 21 | m.reply(`*Song :* ${a.title}\n*Chord :*\n\n${a.chord}`); 22 | } 23 | 24 | handler.help = ['chord ']; 25 | handler.tags = ['tools']; 26 | handler.command = /^(chord)$/i; 27 | 28 | handler.register = true; 29 | handler.limit = true; 30 | 31 | export default handler; 32 | 33 | export async function chord(query) { 34 | return new Promise(async (resolve, reject) => { 35 | const url = `${APIs.ryzumi}/api/search/chord?query=${query}`; 36 | 37 | try { 38 | let { data } = await axios.get(url); 39 | if (data && data.title && data.chord) { 40 | resolve({ 41 | title: decodeHtml(data.title), 42 | chord: data.chord 43 | }); 44 | } else { 45 | reject('No results found'); 46 | } 47 | } catch (error) { 48 | reject('Error fetching data: ' + error.message); 49 | } 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /plugins/tool-shorturl.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | let handler = async (m, { args, usedPrefix, command }) => { 4 | if (!args[0]) return m.reply(`${usedPrefix}${command} https://ryzendesu.com/`) 5 | 6 | try { 7 | const response = await fetch(`https://tr.deployers.repl.co/short?url=${args[0]}`) 8 | 9 | if (response.ok) { 10 | const data = await response.json() 11 | 12 | // Extract relevant data from the response 13 | const bitly = data.bitly 14 | const isgd = data.isgd 15 | const ouo = data.ouo 16 | const tinyurl = data.tinyurl 17 | const vgd = data.vgd 18 | 19 | // Format the data as a list of key-value pairs 20 | const formattedData = `Author: ${author} (github.com/ShirokamiRyzen)\n\nLink Asli ${args[0]}\n=====SHORT LINK=====\nBitly: ${bitly}\nIsgd: ${isgd}\nOuo: ${ouo}\nTinyURL: ${tinyurl}\nVgd: ${vgd}`; 21 | 22 | // Send the formatted data to m.reply 23 | m.reply(formattedData) 24 | } else { 25 | m.reply('Failed to retrieve data. Please try again later.') 26 | } 27 | } catch (error) { 28 | console.error(error); 29 | m.reply('An error occurred. Please try again later.') 30 | } 31 | } 32 | 33 | handler.help = ['short '] 34 | handler.tags = ['internet'] 35 | handler.command = /^(short|singkatin|singkat|bitly|tinyurl|vgd|ouo|isgd|shortlink|linkshort)$/i 36 | 37 | handler.register = true 38 | 39 | export default handler -------------------------------------------------------------------------------- /plugins/downloader-facebook.js: -------------------------------------------------------------------------------- 1 | // Don't delete this credit!!! 2 | // Script by ShirokamiRyzen 3 | 4 | import axios from 'axios' 5 | 6 | let handler = async (m, { conn, args }) => { 7 | if (!args[0]) throw 'Please provide a Facebook video URL'; 8 | 9 | await m.react('🕓') 10 | 11 | try { 12 | const { data } = await axios.get(`${APIs.ryzumi}/api/downloader/fbdl?url=${encodeURIComponent(args[0])}`); 13 | 14 | if (!data.status || !data.data || data.data.length === 0) throw 'No available video found'; 15 | 16 | // Prioritize 720p (HD) and fallback to 360p (SD) 17 | let video = data.data.find(v => v.resolution === '720p (HD)') || data.data.find(v => v.resolution === '360p (SD)'); 18 | 19 | if (video && video.url) { 20 | conn.sendMessage( 21 | m.chat, { 22 | video: { url: video.url }, 23 | mimetype: "video/mp4", 24 | fileName: `video.mp4`, 25 | caption: `Ini kak videonya @${m.sender.split('@')[0]}`, 26 | mentions: [m.sender], 27 | }, { quoted: m }); 28 | 29 | } else { 30 | throw 'No available video found'; 31 | } 32 | } catch (error) { 33 | console.error('Handler Error:', error); 34 | conn.reply(m.chat, `An error occurred: ${error}`, m); 35 | } 36 | } 37 | 38 | handler.help = ['fb '] 39 | handler.tags = ['downloader'] 40 | handler.command = /^(fbdownload|facebook|fb(dl)?)$/i 41 | handler.limit = true 42 | handler.register = true 43 | 44 | export default handler 45 | -------------------------------------------------------------------------------- /plugins/stalk-youtube.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, text }) => { 4 | if (!text || !text.trim()) throw 'Masukkan username yang valid!' 5 | let username = text.trim() 6 | 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | const { data } = await axios.get(`${APIs.ryzumi}/api/stalk/youtube?username=${username}`) 12 | let channel = data.channelMetadata 13 | let videos = data.videoDataList || [] 14 | 15 | let caption = ` 16 | Username: ${channel.username} 17 | Channel URL: ${channel.channelUrl} 18 | External ID: ${channel.externalId} 19 | Subscriber Count: ${channel.subscriberCount ?? 'N/A'} 20 | Video Count: ${channel.videoCount ?? 'N/A'} 21 | Description: ${channel.description} 22 | Family Safe: ${channel.isFamilySafe ? 'Yes' : 'No'} 23 | `.trim() 24 | 25 | if (videos.length > 0) { 26 | caption += '\n\nVideo Terbaru:' 27 | videos.slice(0, 2).forEach((video, index) => { 28 | caption += `\n\nVideo ${index + 1}:\nTitle: ${video.title}\nDuration: ${video.duration}\nLink: https://www.youtube.com${video.navigationUrl}` 29 | }) 30 | } 31 | 32 | await conn.sendMessage(m.chat, { image: { url: channel.avatarUrl }, caption }, { quoted: m }) 33 | } catch (err) { 34 | m.reply('Error: ' + err.message) 35 | } 36 | } 37 | 38 | handler.help = ['ytstalk'] 39 | handler.tags = ['stalk'] 40 | handler.command = /^(ytstalk|youtubestalk)$/i 41 | 42 | handler.register = true 43 | handler.limit = true 44 | 45 | export default handler 46 | -------------------------------------------------------------------------------- /plugins/ai-removebg.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | let handler = async (m, { conn, usedPrefix, text }) => { 5 | try { 6 | await m.react('🕓') 7 | let args = text.trim().split(/\s+/); 8 | let upscale = (args[1] && args[1].toLowerCase() === 'hd') ? "true" : "false"; 9 | 10 | let q = m.quoted ? m.quoted : m; 11 | let mime = (q.msg || q).mimetype || ''; 12 | if (!mime || !mime.startsWith('image/')) throw `Kirim/Reply Gambar dengan caption ${usedPrefix}removebg`; 13 | 14 | 15 | 16 | let media = await q.download(); 17 | let url = await uploadPomf(media); 18 | 19 | let apiUrl = `${APIs.ryzumi}/api/ai/v2/removebg?url=${url}&upscale=${upscale}`; 20 | let response = await fetch(apiUrl); 21 | if (!response.ok) throw new Error('Gagal mengambil gambar dari API'); 22 | 23 | let hasil = Buffer.from(await response.arrayBuffer()); 24 | 25 | await conn.sendFile(m.chat, hasil, 'removedbg.jpg', global.wm, m); 26 | 27 | let epoch = Date.now(); 28 | let random = Math.floor(Math.random() * 99999); 29 | let filename = `removedbg_${random}_${epoch}_file.png`; 30 | 31 | await conn.sendFile(m.chat, hasil, filename, '', m, null, { mimetype: 'image/png', asDocument: true }); 32 | } catch (error) { 33 | m.reply(`Error: ${error.message}`); 34 | } 35 | }; 36 | 37 | handler.help = ['removebg']; 38 | handler.tags = ['ai']; 39 | handler.command = /^(removebg)$/i; 40 | 41 | handler.register = true 42 | handler.limit = 3 43 | 44 | export default handler 45 | -------------------------------------------------------------------------------- /plugins/downloader-aio.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | let handler = async (m, { conn, args, usedPrefix, command }) => { 4 | if (!args[0]) throw `Usage: ${usedPrefix + command} `; 5 | 6 | await m.react('🕓') 7 | 8 | try { 9 | let response = await axios.get(`${APIs.ryzumi}/api/downloader/aiodown?url=${encodeURIComponent(args[0])}`); 10 | let data = response.data; 11 | 12 | if (!data.success) throw 'Gagal mengambil data video'; 13 | 14 | // Cek prioritas kualitas video 15 | let videoUrl; 16 | let qualities = ["hd", "sd", "720p"]; 17 | for (let quality of qualities) { 18 | let video = data.quality.find(v => v.quality.toLowerCase() === quality.toLowerCase()); 19 | if (video) { 20 | videoUrl = video.url; 21 | break; 22 | } 23 | } 24 | 25 | if (!videoUrl) { 26 | let lowestQuality = data.quality.reduce((prev, curr) => { 27 | return parseInt(curr.quality) < parseInt(prev.quality) ? curr : prev; 28 | }); 29 | videoUrl = lowestQuality.url; 30 | } 31 | 32 | let caption = `Ini kak videonya @${m.sender.split('@')[0]}`.trim(); 33 | await conn.sendMessage(m.chat, { video: { url: videoUrl }, caption: caption, mentions: [m.sender], quoted: m }); 34 | 35 | } catch (e) { 36 | throw `Error: ${e.message}`; 37 | } 38 | } 39 | 40 | handler.help = ['aio '] 41 | handler.tags = ['downloader'] 42 | handler.command = /^(aio)$/i 43 | handler.register = true 44 | handler.limit = 1 45 | 46 | export default handler 47 | -------------------------------------------------------------------------------- /plugins/downloader-threads.js: -------------------------------------------------------------------------------- 1 | // Don't delete this credit!!! 2 | // Script by ShirokamiRyzen 3 | 4 | import axios from 'axios' 5 | 6 | let handler = async (m, { conn, args }) => { 7 | if (!args[0]) throw 'Please provide a Threads URL'; 8 | 9 | await m.react('🕓') 10 | 11 | try { 12 | const { data } = await axios.get(`${APIs.ryzumi}/api/downloader/threads?url=${encodeURIComponent(args[0])}`); 13 | 14 | if (!data.success) throw 'Gagal mengambil data dari API'; 15 | 16 | const medias = data.medias || []; 17 | 18 | if (medias.length === 0) { 19 | throw 'No media found in that Threads post'; 20 | } 21 | 22 | for (const item of medias) { 23 | const isVideo = item.type === 'video'; 24 | const isImage = item.type === 'image'; 25 | 26 | if (!isVideo && !isImage) continue; 27 | 28 | await conn.sendMessage( 29 | m.chat, 30 | { 31 | [isVideo ? 'video' : 'image']: { url: item.url }, 32 | caption: `Ini ${isVideo ? 'videonya' : 'fotonya'} kak @${m.sender.split('@')[0]}`, 33 | mentions: [m.sender], 34 | }, 35 | { quoted: m } 36 | ); 37 | } 38 | 39 | } catch (error) { 40 | conn.reply(m.chat, `Terjadi kesalahan: ${error?.message || error}`, m); 41 | } 42 | } 43 | 44 | handler.help = ['threads'].map(v => v + ' '); 45 | handler.tags = ['downloader']; 46 | handler.command = /^(threads(dl)?)$/i; 47 | handler.limit = true 48 | handler.register = true 49 | 50 | export default handler 51 | -------------------------------------------------------------------------------- /plugins/anime-manga.js: -------------------------------------------------------------------------------- 1 | // Update By Xnuvers007 2 | 3 | import fetch from 'node-fetch' 4 | 5 | var handler = async (m, { conn, text }) => { 6 | if (!text) throw `*Masukan Judul Manga Yang Ingin Kamu Cari !*` 7 | conn.reply(m.chat, 'Sedang mencari manga... Silahkan tunggu', m) 8 | let res = await fetch('https://api.jikan.moe/v4/manga?q=' + text) 9 | if (!res.ok) throw 'Tidak Ditemukan' 10 | let json = await res.json() 11 | let { chapters, url, type, score, scored, scored_by, rank, popularity, members, background, status, volumes, synopsis, favorites } = json.data[0] 12 | let judul = json.data[0].titles.map(jud => `${jud.title} [${jud.type}]`).join('\n'); 13 | let xnuvers007 = json.data[0].authors.map(Xnuvers007 => `${Xnuvers007.name} (${Xnuvers007.url})`).join('\n'); 14 | let genrenya = json.data[0].genres.map(xnvrs007 => `${xnvrs007.name}`).join('\n'); 15 | 16 | let animeingfo = `📚 Title: ${judul} 17 | 📑 Chapter: ${chapters} 18 | ✉️ Transmisi: ${type} 19 | 🗂 Status: ${status} 20 | 😎 Genre: ${genrenya} 21 | 🗃 Volumes: ${volumes} 22 | 🌟 Favorite: ${favorites} 23 | 🧮 Score: ${score} 24 | 🧮 Scored: ${scored} 25 | 🧮 Scored BY: ${scored_by} 26 | 🌟 Rank: ${rank} 27 | 🤩 Popularitas: ${popularity} 28 | 👥 Members: ${members} 29 | ⛓️ Url: ${url} 30 | 👨‍🔬 Author: ${xnuvers007} 31 | 📝 Background: ${background} 32 | 💬 Sinopsis: ${synopsis} 33 | ` 34 | conn.sendFile(m.chat, json.data[0].images.jpg.image_url, 'manga.jpg', `*MANGA INFO*\n` + animeingfo, m) 35 | } 36 | handler.help = ['mangainfo '] 37 | handler.tags = ['anime'] 38 | handler.command = /^(mangainfo)$/i 39 | 40 | handler.register = true 41 | 42 | export default handler -------------------------------------------------------------------------------- /plugins/downloader-krakenfiles.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args, usedPrefix, command }) => { 4 | if (!args[0]) 5 | throw `Use example ${usedPrefix}${command} https://krakenfiles.com/view/abYn6V0okV/file.html`; 6 | 7 | let kf = `${APIs.ryzumi}/api/downloader/kfiles?url=${encodeURIComponent(args[0])}`; 8 | 9 | 10 | await m.react('🕓') 11 | 12 | try { 13 | let res = await axios.get(kf); 14 | let data = res.data; 15 | 16 | if (!data || !data.metadata || !data.metadata.download) { 17 | throw 'Failed to fetch download link. Please try again later.'; 18 | } 19 | 20 | let { filename, file_size, type, upload_date, last_download_date, download } = data.metadata; 21 | let apiHeaders = data.headers; 22 | 23 | let caption = ` 24 | *💌 Name:* ${filename} 25 | *📊 Size:* ${file_size} 26 | *🗂️ Extension:* ${type} 27 | *📨 Uploaded:* ${upload_date} 28 | *⌛ Last Download:* ${last_download_date} 29 | `.trim(); 30 | 31 | let fileRes = await axios.get(download, { 32 | headers: apiHeaders, 33 | responseType: 'arraybuffer' 34 | }); 35 | 36 | m.reply(caption); 37 | await conn.sendFile(m.chat, Buffer.from(fileRes.data), filename, '', m, null, { mimetype: type, asDocument: true }); 38 | } catch (e) { 39 | throw 'An error occurred: ' + e; 40 | } 41 | }; 42 | 43 | handler.help = ['krakenfiles'].map(v => v + ' '); 44 | handler.tags = ['downloader']; 45 | handler.command = /^(kfiles|kf|krakenfiles)$/i; 46 | 47 | handler.limit = true 48 | handler.register = true 49 | 50 | export default handler 51 | -------------------------------------------------------------------------------- /plugins/owner-kick.js: -------------------------------------------------------------------------------- 1 | import { areJidsSameUser } from '@whiskeysockets/baileys' 2 | 3 | var handler = async (m, { conn, participants, botAdmin, text }) => { 4 | if (!botAdmin) { 5 | return m.reply('Bot Bukan Admin T-T') 6 | } 7 | // Resolve target from reply/mention/number 8 | const rawWho = m.quoted?.sender || (m.mentionedJid && m.mentionedJid[0]) || (text ? (text.replace(/\D/g, '') + '@s.whatsapp.net') : '') 9 | if (!rawWho) throw 'Reply / tag yang ingin di kick' 10 | 11 | // Normalize JID (handle device part and @lid mapping if available) 12 | const who = typeof conn.getJid === 'function' ? conn.getJid(rawWho) : (rawWho.decodeJid ? rawWho.decodeJid() : rawWho) 13 | 14 | if (areJidsSameUser(who, m.sender)) throw 'Reply / tag yang ingin di kick' 15 | 16 | // Normalize participant JIDs and check membership robustly 17 | const parts = participants 18 | .map(p => p?.id || p?.jid || p?.participant || p?.lid) 19 | .filter(Boolean) 20 | .map(raw => ({ raw, norm: (typeof conn.getJid === 'function' ? conn.getJid(raw) : (raw.decodeJid ? raw.decodeJid() : raw)) })) 21 | 22 | const matched = parts.find(p => areJidsSameUser(p.norm, who)) 23 | if (!matched) throw 'Target tidak berada dalam Grup !' 24 | 25 | // Use the exact raw JID present in participants to avoid format mismatch 26 | await conn.groupParticipantsUpdate(m.chat, [matched.raw], 'remove') 27 | m.reply(`Success`) 28 | } 29 | handler.help = ['kick', '-'].map(v => 'o' + v + ' @user') 30 | handler.tags = ['owner'] 31 | handler.command = /^(okick|o-)$/i 32 | 33 | handler.owner = true 34 | handler.group = true 35 | handler.botAdmin = true 36 | 37 | export default handler 38 | 39 | const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) 40 | -------------------------------------------------------------------------------- /plugins/tool-uploader.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | let handler = async (m) => { 5 | try { 6 | let q = m.quoted ? m.quoted : m; 7 | let mime = (q.msg || q).mimetype || ''; 8 | if (!mime) throw 'No media found'; 9 | 10 | let media = await q.download(); 11 | 12 | let link = await ryzenCDN(media); 13 | if (!link) throw 'Failed to upload media'; 14 | let fileUrl = typeof link === 'object' ? link.url : link; 15 | 16 | let caption = `📮 *L I N K :* 17 | ${fileUrl} 18 | 📊 *S I Z E :* ${media.length} Byte 19 | 📛 *E x p i r e d :* 24 Hours 20 | 21 | *S H O R T :* ${await shortUrl(fileUrl)}`; 22 | 23 | await conn.reply(m.chat, caption, m, { 24 | contextInfo: { 25 | externalAdReply: { 26 | mediaUrl: sgh, 27 | mediaType: 2, 28 | title: wm, 29 | body: botdate, 30 | thumbnail: Buffer.from(await (await fetch(fileUrl)).arrayBuffer()), 31 | sourceUrl: fileUrl, 32 | }, 33 | }, 34 | }); 35 | } catch (error) { 36 | console.error('Error in handler:', error); 37 | conn.reply(m.chat, `Error: ${error.message || error}`, m); 38 | } 39 | }; 40 | 41 | handler.help = ['upload'] 42 | handler.tags = ['tools'] 43 | handler.command = /^(tourl|upload)$/i 44 | 45 | handler.register = true 46 | 47 | export default handler 48 | 49 | async function shortUrl(url) { 50 | try { 51 | let res = await fetch(`https://tinyurl.com/api-create.php?url=${encodeURIComponent(url)}`); 52 | if (!res.ok) throw new Error('Failed to shorten URL'); 53 | return await res.text(); 54 | } catch (error) { 55 | console.error('Error in shortUrl:', error); 56 | return url; 57 | } 58 | } -------------------------------------------------------------------------------- /plugins/internet-ssweb.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, text, command, usedPrefix }) => { 4 | if (!text) return m.reply(`Gunakan format ${usedPrefix + command} \n\n*Contoh :* ${usedPrefix + command} https://github.com/ShirokamiRyzen`); 5 | 6 | 7 | await m.react('🕓') 8 | 9 | if (!text.startsWith('https://') && !text.startsWith('http://')) { 10 | text = 'https://' + text; 11 | } 12 | 13 | const ssweb = async (url, mode) => { 14 | try { 15 | let response = await axios.get(`${APIs.ryzumi}/api/tool/ssweb`, { 16 | params: { url, mode }, 17 | responseType: 'arraybuffer' 18 | }); 19 | return response.data; 20 | } catch (err) { 21 | console.error(err); 22 | return null; 23 | } 24 | }; 25 | 26 | let screenshot; 27 | if (command === 'sshp') { 28 | screenshot = await ssweb(text, 'handphone'); 29 | } else if (command === 'sspc') { 30 | screenshot = await ssweb(text, 'desktop'); 31 | } else if (command === 'ssweb') { 32 | screenshot = await ssweb(text, 'desktop'); 33 | } 34 | if (!screenshot) { 35 | return m.reply("Gagal mengambil screenshot. Pastikan URL valid atau coba lagi nanti."); 36 | } 37 | 38 | let res = `Screenshot untuk ${text}`; 39 | 40 | await conn.sendMessage(m.chat, { 41 | image: screenshot, 42 | caption: res 43 | }, { quoted: m }); 44 | }; 45 | 46 | handler.help = ['ssweb', 'sspc', 'sshp'].map(v => v + ' '); 47 | handler.tags = ['internet']; 48 | handler.command = /^(ssweb|sspc|sshp)$/i; 49 | 50 | handler.limit = 1 51 | handler.register = true 52 | 53 | export default handler 54 | -------------------------------------------------------------------------------- /plugins/ai-upscale.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | let handler = async (m, { conn, usedPrefix, command, text }) => { 5 | try { 6 | await m.react('🕓') 7 | const arg = (text || '').trim().split(/\s+/)[0] 8 | let scale = Number(arg) 9 | if (!arg) { 10 | scale = 2 11 | } else if (!Number.isInteger(scale) || ![1, 2, 3, 4].includes(scale)) { 12 | return m.reply( 13 | `Pilihan tidak valid.\nGunakan angka 1-4.\nContoh:\n• ${usedPrefix + command} 2\n• ${usedPrefix + command} 4` 14 | ) 15 | } 16 | 17 | let who = m.mentionedJid && m.mentionedJid[0] ? m.mentionedJid[0] : m.fromMe ? conn.user.jid : m.sender 18 | await conn.getName(who) 19 | 20 | let q = m.quoted ? m.quoted : m 21 | let mime = (q.msg || q).mimetype || '' 22 | if (!mime) throw 'Kirim/Reply Gambar dengan caption .upscale <1|2|3|4>' 23 | 24 | 25 | 26 | let media = await q.download() 27 | let url = await uploadPomf(media) 28 | 29 | const apiUrl = `https://api.siputzx.my.id/api/tools/upscale?url=${encodeURIComponent(url)}&scale=${scale}` 30 | 31 | const response = await fetch(apiUrl) 32 | if (!response.ok) { 33 | const txt = await response.text().catch(() => '') 34 | throw new Error(`Upscale gagal (${response.status}). ${txt || ''}`.trim()) 35 | } 36 | 37 | const hasil = Buffer.from(await response.arrayBuffer()) 38 | 39 | await conn.sendFile(m.chat, hasil, 'hasil.png', global.wm, m) 40 | } catch (error) { 41 | console.error(error) 42 | m.reply('Internal server error') 43 | } 44 | } 45 | 46 | handler.help = ['upscale'] 47 | handler.tags = ['ai'] 48 | handler.command = /^(hd|upscale)$/i 49 | 50 | handler.register = true 51 | handler.limit = 10 52 | 53 | export default handler 54 | -------------------------------------------------------------------------------- /plugins/internet-lens.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | let handler = async (m, { conn }) => { 5 | 6 | await m.react('🕓') 7 | 8 | try { 9 | let q = m.quoted ? m.quoted : m 10 | let mime = (q.msg || q).mimetype || '' 11 | if (!mime) throw 'Kirim/Reply gambar dengan perintah .googlelens' 12 | 13 | let media = await q.download() 14 | if (!media) throw 'Gagal mendownload gambar!' 15 | 16 | let cdnResult = await ryzenCDN(media) 17 | if (!cdnResult || !cdnResult.url) throw 'Gagal upload ke CDN!' 18 | 19 | let url = cdnResult.url 20 | let res = await axios.get(`${APIs.ryzumi}/api/search/lens`, { 21 | params: { url }, 22 | }) 23 | 24 | if (!res.data?.result?.length) throw 'Tidak ditemukan hasil dari Google Lens.' 25 | 26 | let teks = `🔎 *Google Lens Results (Full Detail)*\n\n` 27 | 28 | for (let r of res.data.result) { 29 | teks += `📌 *Position:* ${r.position}\n` 30 | teks += `📖 *Title:* ${r.title}\n` 31 | teks += `🔗 *Page Link:* ${r.link}\n` 32 | teks += `🖼️ *Image:* ${r.image?.link || '-'}\n` 33 | teks += `📏 *Image Size:* ${r.image?.width}x${r.image?.height}\n` 34 | teks += `📍 *Source:* ${r.source}\n` 35 | teks += `🖼️ *Thumbnail:* ${r.thumbnail}\n\n` 36 | } 37 | 38 | await conn.reply(m.chat, teks.trim(), m) 39 | 40 | } catch (err) { 41 | console.error(err) 42 | m.reply(err.message || 'Error internal server') 43 | } 44 | } 45 | 46 | handler.help = ['lens'] 47 | handler.tags = ['internet'] 48 | handler.command = /^(googlelens|lens)$/i 49 | handler.register = true 50 | handler.limit = 2 51 | 52 | export default handler 53 | -------------------------------------------------------------------------------- /plugins/_memfess-answer.js: -------------------------------------------------------------------------------- 1 | import { uploadPomf } from '../lib/uploadImage.js' 2 | 3 | export async function before(m) { 4 | if (!m.chat.endsWith('@s.whatsapp.net')) return !0 5 | 6 | const raw = m.message || {} 7 | const mtype = m.mtype || (Object.keys(raw)[0] || '') 8 | const isSystem = 9 | mtype === 'protocolMessage' || 10 | !!raw.protocolMessage || 11 | !!m.messageStubType || 12 | !!raw.senderKeyDistributionMessage || 13 | !!raw.extendedTextMessage?.contextInfo?.disappearingMode 14 | if (isSystem) return !0 15 | 16 | this.menfess = this.menfess || {} 17 | const mf = Object.values(this.menfess).find(v => v.status === false && v.penerima === m.sender) 18 | if (!mf) return !0 19 | 20 | const bodyText = (m.text || '').trim() 21 | 22 | let q = null 23 | if (m.quoted && typeof m.quoted.download === 'function') q = m.quoted 24 | else if (typeof m.download === 'function') q = m 25 | 26 | let mediaUrl = null 27 | if (q) { 28 | try { 29 | const buf = await q.download() 30 | if (buf && Buffer.isBuffer(buf)) { 31 | mediaUrl = await uploadPomf(buf) 32 | } 33 | } catch { } 34 | } 35 | 36 | if (!bodyText && !mediaUrl) return !0 37 | 38 | let caption = `Hai kak, kamu menerima balasan nih.\n\n` 39 | if (bodyText) caption += `Pesan balasannya:\n${bodyText}\n` 40 | 41 | if (mediaUrl) { 42 | await this.sendMessage(mf.dari, { 43 | image: { url: String(mediaUrl) }, 44 | caption 45 | }) 46 | } else { 47 | await this.sendMessage(mf.dari, { text: caption }) 48 | } 49 | 50 | await m.reply('Balasan Memfess terkirim.') 51 | await this.delay(1000) 52 | delete this.menfess[mf.id] 53 | return !0 54 | } 55 | -------------------------------------------------------------------------------- /plugins/owner-deluser.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, text }) => { 2 | function no(number) { 3 | return number.replace(/\s/g, '').replace(/([@+-])/g, ''); 4 | } 5 | 6 | let numbers = text.split(/\s+/).map(no); 7 | 8 | if (!numbers.length && !m.quoted) { 9 | return conn.reply(m.chat, `*❏ DELETE USER*\n\nTag user, tulis nomor, atau balas member yang ingin di RESET`, m); 10 | } 11 | 12 | let deletedUsers = []; 13 | 14 | for (let i = 0; i < numbers.length; i++) { 15 | let number = numbers[i]; 16 | 17 | if (isNaN(number) || number.length > 15) { 18 | conn.reply(m.chat, `*❏ DELETE USER*\n\nNomor '${number}' tidak valid!`, m); 19 | continue; 20 | } 21 | 22 | let user = number + '@s.whatsapp.net'; 23 | let groupMetadata = m.isGroup ? await conn.groupMetadata(m.chat) : {}; 24 | let participants = m.isGroup ? groupMetadata.participants : []; 25 | let users = m.isGroup ? participants.find(u => u.jid == user) : {}; 26 | 27 | if (users) { 28 | delete global.db.data.users[user]; 29 | deletedUsers.push(`@${number}`); 30 | } else { 31 | conn.reply(m.chat, `*❏ DELETE USER*\n\nUser dengan nomor @${number} tidak ditemukan di grup ini!`, m); 32 | } 33 | } 34 | 35 | if (deletedUsers.length > 0) { 36 | conn.reply(m.chat, `*❏ DELETE USER*\n\nBerhasil menghapus ${deletedUsers.join(', ')} dari *DATABASE*`, null, { 37 | contextInfo: { 38 | mentionedJid: deletedUsers.map(u => u + '@s.whatsapp.net') 39 | } 40 | }); 41 | } 42 | } 43 | 44 | handler.help = ['deluser'] 45 | handler.tags = ['owner'] 46 | handler.command = /^(deluser|deleteuser|ha?pu?su(ser)?)$/i 47 | 48 | handler.owner = true 49 | 50 | export default handler -------------------------------------------------------------------------------- /plugins/downloader-terabox.js: -------------------------------------------------------------------------------- 1 | 2 | import axios from 'axios' 3 | 4 | let handler = async (m, { conn, args }) => { 5 | if (!args[0]) throw 'Please provide a Terabox URL'; 6 | 7 | await m.react('🕓') 8 | 9 | try { 10 | const { data } = await axios.get(`${APIs.ryzumi}/api/downloader/terabox`, { 11 | params: { url: args[0] } 12 | }); 13 | 14 | if (data.status !== 'ok') throw 'Failed to fetch data or invalid URL'; 15 | 16 | const file = data.list && data.list.length > 0 ? data.list[0] : {}; 17 | const downloadUrl = data.dlink || file.dlink; 18 | const filename = file.server_filename || 'file'; 19 | const size = file.size ? formatSize(parseInt(file.size)) : 'Unknown'; 20 | 21 | if (!downloadUrl) throw 'No download link found'; 22 | 23 | await conn.sendMessage(m.chat, { 24 | document: { url: downloadUrl }, 25 | fileName: filename, 26 | mimetype: 'application/octet-stream', 27 | caption: `*Filename:* ${filename}\n*Size:* ${size}\n\n_Powered by Ryzumi API_` 28 | }, { quoted: m }); 29 | 30 | } catch (error) { 31 | console.error('Handler Error:', error); 32 | conn.reply(m.chat, `Terjadi kesalahan: ${error?.message || error}`, m); 33 | } 34 | } 35 | 36 | function formatSize(bytes) { 37 | if (!bytes || bytes === 0) return '0 B'; 38 | const k = 1024; 39 | const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; 40 | const i = Math.floor(Math.log(bytes) / Math.log(k)); 41 | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; 42 | } 43 | 44 | handler.help = ['terabox'].map(v => v + ' '); 45 | handler.tags = ['downloader']; 46 | handler.command = /^(terabox|tera)$/i; 47 | handler.limit = true 48 | handler.register = true 49 | 50 | export default handler 51 | -------------------------------------------------------------------------------- /plugins/owner-exec.js: -------------------------------------------------------------------------------- 1 | import syntaxerror from 'syntax-error' 2 | import { format } from 'util' 3 | import { fileURLToPath } from 'url' 4 | import { dirname } from 'path' 5 | import { createRequire } from 'module' 6 | 7 | const __dirname = dirname(fileURLToPath(import.meta.url)) 8 | const require = createRequire(__dirname) 9 | 10 | let handler = async (m, _2) => { 11 | let { conn, usedPrefix, noPrefix, args, groupMetadata } = _2 12 | let _return 13 | let _syntax = '' 14 | let _text = (/^=/.test(usedPrefix) ? 'return ' : '') + noPrefix 15 | let old = m.exp * 1 16 | try { 17 | let i = 15 18 | let f = { 19 | exports: {} 20 | } 21 | let exec = new (async () => { }).constructor('print', 'm', 'handler', 'require', 'conn', 'Array', 'process', 'args', 'groupMetadata', 'module', 'exports', 'argument', _text) 22 | _return = await exec.call(conn, (...args) => { 23 | if (--i < 1) return 24 | console.log(...args) 25 | return conn.reply(m.chat, format(...args), m) 26 | }, m, handler, require, conn, CustomArray, process, args, groupMetadata, f, f.exports, [conn, _2]) 27 | } catch (e) { 28 | let err = syntaxerror(_text, 'Execution Function', { 29 | allowReturnOutsideFunction: true, 30 | allowAwaitOutsideFunction: true, 31 | sourceType: 'module' 32 | }) 33 | if (err) _syntax = '```' + err + '```\n\n' 34 | _return = e 35 | } finally { 36 | conn.reply(m.chat, _syntax + format(_return), m) 37 | m.exp = old 38 | } 39 | } 40 | handler.help = ['> ', '=> '] 41 | handler.tags = ['advanced'] 42 | handler.customPrefix = /^=?> / 43 | handler.command = /(?:)/i 44 | 45 | handler.owner = true 46 | 47 | export default handler 48 | 49 | class CustomArray extends Array { 50 | constructor(...args) { 51 | if (typeof args[0] == 'number') return super(Math.min(args[0], 10000)) 52 | else return super(...args) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /plugins/downloader-mega.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args, usedPrefix, text, command }) => { 4 | try { 5 | if (!text) throw `Contoh:\n${usedPrefix + command} https://mega.nz/file/NnEA1DIT#GXPSel8LJk2mnp7E_i69OXkSGq-x_bLceIi63p3BNZk` 6 | 7 | const { data } = await axios.get(`${APIs.ryzumi}/api/downloader/mega?url=${encodeURIComponent(text)}`, { headers: { accept: 'application/json' } }) 8 | const item = data?.result?.find(x => x.type === 'file') || data?.result?.[0] 9 | if (!item) return m.reply('Error: File tidak ditemukan') 10 | if (!item.link) return m.reply('Error: Link unduhan tidak tersedia') 11 | 12 | if (item.size >= 500_000_000) return m.reply('Error: ukuran file terlalu besar (Ukuran Max: 500MB)') 13 | 14 | m.reply(`*_Mohon tunggu sebentar..._*\n${item.name} sedang diproses...`) 15 | 16 | const ext = (item.name.split('.').pop() || '').toLowerCase() 17 | const mimeMap = { 18 | mp4: 'video/mp4', 19 | pdf: 'application/pdf', 20 | zip: 'application/zip', 21 | rar: 'application/x-rar-compressed', 22 | '7z': 'application/x-7z-compressed', 23 | jpg: 'image/jpeg', 24 | jpeg: 'image/jpeg', 25 | png: 'image/png', 26 | apk: 'application/vnd.android.package-archive', 27 | mp3: 'audio/mpeg', 28 | wav: 'audio/wav' 29 | } 30 | const mimetype = mimeMap[ext] || 'application/octet-stream' 31 | 32 | conn.sendMessage( 33 | m.chat, 34 | { document: { url: item.link }, mimetype, filename: item.name }, 35 | { quoted: m } 36 | ) 37 | } catch (error) { 38 | console.log(error) 39 | return m.reply(`Error: ${error?.message || error}`) 40 | } 41 | } 42 | 43 | handler.help = ['mega'] 44 | handler.tags = ['downloader'] 45 | handler.command = /^(mega)$/i 46 | 47 | handler.limit = true 48 | handler.register = true 49 | 50 | export default handler 51 | -------------------------------------------------------------------------------- /plugins/stalk-wa.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment-timezone' 2 | import PhoneNum from 'awesome-phonenumber' 3 | 4 | let regionNames = new Intl.DisplayNames(['en'], { type: 'region' }) 5 | 6 | let handler = async (m, { conn, text, usedPrefix, command: cmd }) => { 7 | let num = m.quoted?.sender || m.mentionedJid?.[0] || text 8 | if (!num) throw `Ex: ${usedPrefix + cmd} @tag / 628xxx` 9 | num = num.replace(/\D/g, '') + '@s.whatsapp.net' 10 | if (!(await conn.onWhatsApp(num))[0]?.exists) throw 'User not exists' 11 | let img = await conn.profilePictureUrl(num, 'image').catch(_ => './src/avatar_contact.png') 12 | let bio = await conn.fetchStatus(num).catch(_ => { }) 13 | let name = await conn.getName(num) 14 | let business = await conn.getBusinessProfile(num) 15 | let format = PhoneNum(`+${num.split('@')[0]}`) 16 | let country = regionNames.of(format.getRegionCode('international')) 17 | let wea = `\t\t\t\t*▾ WHATSAPP ▾*\n\n*° Country :* ${country.toUpperCase()}\n*° Name :* ${name ? name : '-'}\n*° Format Number :* ${format.getNumber('international')}\n*° Url Api :* wa.me/${num.split('@')[0]}\n*° Mentions :* @${num.split('@')[0]}\n*° Status :* ${bio?.status || '-'}\n*° Date Status :* ${bio?.setAt ? moment(bio.setAt.toDateString()).locale('id').format('LL') : '-'}\n\n${business ? `\t\t\t\t*▾ INFO BUSINESS ▾*\n\n*° BusinessId :* ${business.wid}\n*° Website :* ${business.website ? business.website : '-'}\n*° Email :* ${business.email ? business.email : '-'}\n*° Category :* ${business.category}\n*° Address :* ${business.address ? business.address : '-'}\n*° Timeone :* ${business.business_hours.timezone ? business.business_hours.timezone : '-'}\n*° Descripcion* : ${business.description ? business.description : '-'}` : '*Standard WhatsApp Account*'}` 18 | img ? await conn.sendMessage(m.chat, { image: { url: img }, caption: wea, mentions: [num] }, { quoted: m }) : m.reply(wea) 19 | } 20 | 21 | handler.help = ['wastalk'] 22 | handler.tags = ['stalk'] 23 | handler.command = /^(wa|whatsapp)stalk$/i 24 | 25 | handler.register = true 26 | 27 | export default handler -------------------------------------------------------------------------------- /plugins/levelup.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { canLevelUp, xpRange } from '../lib/levelling.js'; 3 | 4 | let handler = async (m, { conn, usedPrefix }) => { 5 | let who = m.sender; 6 | let name = conn.getName(m.sender); 7 | let discriminator = who.substring(9, 13); 8 | let pp = 'https://i.pinimg.com/564x/d4/17/75/d41775c2a051fe94269e71bdcbd240a5.jpg'; 9 | 10 | try { 11 | pp = await conn.profilePictureUrl(m.sender, 'image'); 12 | } catch (e) { 13 | } finally { 14 | let user = global.db.data.users[m.sender]; 15 | let { min, xp, max } = xpRange(user.level, global.multiplier); 16 | 17 | if (!canLevelUp(user.level, user.exp, global.multiplier)) { 18 | await conn.reply(m.chat, `Level ${name} ${user.level} (${user.exp - min}/${xp})\nKurang ${max - user.exp} EXP lagi!`.trim(), m); 19 | } 20 | 21 | let before = user.level * 1; 22 | 23 | while (canLevelUp(user.level, user.exp, global.multiplier)) { 24 | user.level++; 25 | } 26 | 27 | if (before !== user.level) { 28 | await conn.reply(m.chat, `${name} Level Up!\n_${before}_ -> ${user.level}`.trim(), m); 29 | } 30 | // Mengirim gambar profil 31 | await conn.sendFile(m.chat, pp, 'profile.jpg', 'Ini foto profil kamu!', m); 32 | 33 | // Jeda agar pesan terlihat berurutan 34 | await new Promise(resolve => setTimeout(resolve, 2000)); 35 | 36 | } 37 | } 38 | 39 | handler.help = ['levelup']; 40 | handler.tags = ['xp']; 41 | handler.command = /^levelup$/i; 42 | 43 | export default handler; 44 | function sort(property, ascending = true) { 45 | if (property) return (...args) => args[ascending & 1][property] - args[!ascending & 1][property] 46 | else return (...args) => args[ascending & 1] - args[!ascending & 1] 47 | } 48 | 49 | function toNumber(property, _default = 0) { 50 | if (property) return (a, i, b) => { 51 | return { ...b[i], [property]: a[property] === undefined ? _default : a[property] } 52 | } 53 | else return a => a === undefined ? _default : a 54 | } 55 | 56 | function enumGetKey(a) { 57 | return a.jid 58 | } 59 | -------------------------------------------------------------------------------- /plugins/owner-simulate.js: -------------------------------------------------------------------------------- 1 | let handler = async (m, { conn, usedPrefix, command, args: [event], text }) => { 2 | if (!event) return await conn.reply(m.chat, `Contoh: 3 | ${usedPrefix + command} welcome @user 4 | ${usedPrefix + command} bye @user 5 | ${usedPrefix + command} promote @user 6 | ${usedPrefix + command} demote @user 7 | 8 | Bisa juga kirim nomor langsung: ${usedPrefix + command} welcome 62812xxxxxxx`.trim(), m, null, [['Welcome', '#simulate welcome'], ['Bye', '#simulate bye']]) 9 | 10 | // Collect targets from mentions or raw numbers, normalize to JIDs 11 | const rest = text?.slice(event.length).trim() || '' 12 | const whoFromMention = conn.parseMention(rest) 13 | const whoFromNumbers = (rest.match(/\b\d{5,16}\b/g) || []).map(v => v + '@s.whatsapp.net') 14 | let partRaw = [...new Set([...(whoFromMention || []), ...whoFromNumbers])] 15 | if (!partRaw.length) partRaw = [m.sender] 16 | const part = await Promise.all(partRaw.map(async j => conn.getJid ? await conn.getJid(j, m.chat) : j)) 17 | 18 | let act = false 19 | m.reply(`Simulating ${event}...`) 20 | switch (event.toLowerCase()) { 21 | case 'add': 22 | case 'invite': 23 | case 'welcome': 24 | act = 'add' 25 | break 26 | case 'bye': 27 | case 'kick': 28 | case 'leave': 29 | case 'remove': 30 | act = 'remove' 31 | break 32 | case 'promote': 33 | act = 'promote' 34 | break 35 | case 'demote': 36 | act = 'demote' 37 | break 38 | default: 39 | return conn.reply(m.chat, 'Event harus salah satu dari: welcome/bye/promote/demote', m) 40 | } 41 | if (act) return conn.participantsUpdate({ 42 | id: m.chat, 43 | participants: part, 44 | action: act, 45 | simulate: true 46 | }) 47 | } 48 | handler.help = ['simulate [@mention]'] 49 | handler.tags = ['owner'] 50 | handler.rowner = true 51 | 52 | handler.command = /^(simulate|simulasi)$/i 53 | export default handler -------------------------------------------------------------------------------- /plugins/internet-gag.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import moment from 'moment-timezone' 3 | 4 | let handler = async (m, { conn }) => { 5 | 6 | 7 | 8 | await m.react('🕓') 9 | 10 | try { 11 | const { data } = await axios.get(`${APIs.ryzumi}/api/tool/growagarden`) 12 | const garden = data.data 13 | 14 | let teks = `🌼 *Grow a Garden Inventory* 🌼\n\n` 15 | 16 | const formatItem = (item) => { 17 | let time = moment(item.lastUpdated).tz('Asia/Jakarta').format('DD MMM YYYY, HH:mm:ss') + ' WIB' 18 | return `• ${item.name} (${item.quantity})\n ↳ Available: ${item.available ? '✅' : '❌'} | Updated: ${time}\n` 19 | } 20 | 21 | // Seeds 22 | teks += `🌱 *Seeds*\n` 23 | garden.seeds.forEach(s => { 24 | teks += formatItem(s) 25 | }) 26 | 27 | // Gear 28 | teks += `\n🧰 *Gear*\n` 29 | garden.gear.forEach(g => { 30 | teks += formatItem(g) 31 | }) 32 | 33 | // Eggs 34 | teks += `\n🥚 *Eggs*\n` 35 | garden.eggs.forEach(e => { 36 | teks += formatItem(e) 37 | }) 38 | 39 | // Cosmetics 40 | teks += `\n🎀 *Cosmetics*\n` 41 | garden.cosmetics.forEach(c => { 42 | teks += formatItem(c) 43 | }) 44 | 45 | // Honey Items 46 | teks += `\n🍯 *Event/Honey Items*\n` 47 | garden.honey.forEach(h => { 48 | teks += formatItem(h) 49 | }) 50 | 51 | // Weather 52 | let weather = garden.weather 53 | teks += `\n⛅ *Cuaca Sekarang:* ${weather.type.toUpperCase()}\n` 54 | weather.effects.forEach(eff => { 55 | teks += `- ${eff}\n` 56 | }) 57 | let weatherUpdated = moment(weather.lastUpdated).tz('Asia/Jakarta').format('DD MMM YYYY, HH:mm:ss') + ' WIB' 58 | teks += `🕒 Update Cuaca: ${weatherUpdated}\n` 59 | 60 | await conn.reply(m.chat, teks.trim(), m) 61 | } catch (err) { 62 | m.reply('Error\n\n' + err.message) 63 | } 64 | } 65 | 66 | handler.help = ['growagarden'] 67 | handler.tags = ['internet'] 68 | handler.command = /^(growagarden|ggarden|gag)$/i 69 | 70 | handler.register = true 71 | handler.limit = true 72 | 73 | export default handler 74 | -------------------------------------------------------------------------------- /plugins/owner-join.js: -------------------------------------------------------------------------------- 1 | let linkRegex = /chat.whatsapp.com\/([0-9A-Za-z]{20,24})( [0-9]{1,3})?/i; 2 | 3 | let handler = async (m, { conn, text, isOwner }) => { 4 | let [_, code, expired] = text.match(linkRegex) || []; 5 | if (!code) throw 'Link invalid!\n\nContoh: .join https://chat.whatsapp.com/... 30'; 6 | let res; 7 | try { 8 | res = await conn.groupAcceptInvite(code); 9 | } catch (error) { 10 | if (error && error.message) { 11 | if (error.message.includes('not-authorized')) { 12 | return m.reply(` 13 | Tidak dapat bergabung karena sebelumnya terkena kick 14 | Silahkan tunggu max 7 hari, jangan SPAM!!! 15 | 16 | Note: Laporan apapun tentang ini tidak akan ditanggapi oleh Owner 17 | `); 18 | } else if (error.message.includes('gone')) { 19 | return m.reply('Link tidak valid/sudah diatur ulang oleh admin'); 20 | } 21 | } 22 | throw error; 23 | } 24 | 25 | let user = global.db.data.users[m.sender]; 26 | let now = Date.now(); 27 | let maxTime = Math.floor((user.premiumTime - now) / (1000 * 60 * 60 * 24)); // calculate remaining premium time in days 28 | 29 | expired = Math.floor(Math.min(maxTime, Math.max(1, isOwner ? (isNumber(expired) ? parseInt(expired) : 0) : 3))); 30 | if (expired > maxTime) { 31 | return m.reply(`Max durasi grup mengikuti durasi premium anda\nMaximum hari anda adalah ${maxTime}`); 32 | } 33 | 34 | m.reply(`Berhasil join grup ${res}${expired ? ` selama ${expired} hari 35 | 36 | Jika grup menggunakan persetujuan admin, silahkan ACC nomor ini` : ''}`); 37 | let chats = global.db.data.chats[res]; 38 | if (!chats) chats = global.db.data.chats[res] = {}; 39 | if (expired) chats.expired = +new Date() + expired * 1000 * 60 * 60 * 24; 40 | }; 41 | 42 | handler.help = ['join']; 43 | handler.tags = ['owner']; 44 | 45 | handler.command = /^join$/i 46 | handler.rowner = false 47 | handler.premium = true 48 | 49 | export default handler 50 | 51 | const isNumber = (x) => (x = parseInt(x), typeof x === 'number' && !isNaN(x)); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ryzumi-esm", 3 | "version": "10.0.0", 4 | "description": "BOT Whatsapp", 5 | "main": "index.js", 6 | "type": "module", 7 | "directories": { 8 | "lib": "lib", 9 | "src": "src", 10 | "plugins": "plugins" 11 | }, 12 | "scripts": { 13 | "start": "node index.js", 14 | "dev": "nodemon --experimental-specifier-resolution=node index.js" 15 | }, 16 | "keywords": [ 17 | "termux-whatsapp-bot", 18 | "whatsapp-bot", 19 | "whatsapp", 20 | "js-whatsapp", 21 | "whatsapp", 22 | "Games-wabot", 23 | "wabot-aq", 24 | "multi-device", 25 | "MD", 26 | "baileys-md" 27 | ], 28 | "homepage": "https://github.com/ShirokamiRyzenRyzumiMD-ESM", 29 | "author": { 30 | "name": "ShirokamiRyzen" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/ShirokamiRyzenRyzumiMD-ESM.git" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/ShirokamiRyzenRyzumiMD-ESM/issues" 38 | }, 39 | "license": "GPL-3.0-or-later", 40 | "dependencies": { 41 | "@vitalets/google-translate-api": "^9.2.0", 42 | "@whiskeysockets/baileys": "^7.0.0-rc.6", 43 | "awesome-phonenumber": "^3.4.0", 44 | "axios": "^1.12.2", 45 | "cfonts": "^2.10.0", 46 | "chalk": "^5.1.0", 47 | "cheerio": "1.0.0-rc.12", 48 | "file-type": "^17.1.1", 49 | "fluent-ffmpeg": "^2.1.2", 50 | "human-readable": "^0.2.1", 51 | "jimp": "^1.6.0", 52 | "jsdom": "^22.1.0", 53 | "lowdb": "^3.0.0", 54 | "mime-types": "^2.1.35", 55 | "moment-timezone": "^0.5.43", 56 | "node-fetch": "^3.3.2", 57 | "node-gtts": "^2.0.2", 58 | "node-os-utils": "^1.3.7", 59 | "node-webpmux": "^3.2.0", 60 | "ocr-space-api-wrapper": "^2.3.0", 61 | "similarity": "^1.2.1", 62 | "syntax-error": "^1.4.0", 63 | "yargs": "^17.1.1", 64 | "yt-search": "^2.10.4" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /plugins/anime-imagesearch.js: -------------------------------------------------------------------------------- 1 | //Dont delete this credit!!! 2 | //Script by ShirokamiRyzen 3 | 4 | import fetch from 'node-fetch' 5 | import { uploadPomf } from '../lib/uploadImage.js' 6 | 7 | let handler = async (m, { conn, usedPrefix, command }) => { 8 | try { 9 | await m.react('🕓') 10 | let q = m.quoted ? m.quoted : m; 11 | let mime = (q.msg || q).mimetype || ''; 12 | if (!mime) throw `Kirim/Reply Gambar dengan caption ${usedPrefix + command}`; 13 | 14 | 15 | 16 | let media = await q.download(); 17 | let url = await uploadPomf(media); 18 | let hasil = await fetch(`https://api.trace.moe/search?cutBorders&url=${encodeURIComponent(url)}`); 19 | let response = await hasil.json(); 20 | 21 | if (response && response.result && response.result.length > 0) { 22 | let firstResult = response.result[0]; 23 | 24 | let filename = firstResult.filename; 25 | let episode = firstResult.episode; 26 | let similarity = Math.round(firstResult.similarity * 100); 27 | let videoURL = firstResult.video; 28 | let videoIMG = firstResult.image; 29 | 30 | let captionVid = `Name: ${filename}\nEpisode: ${episode}\n\nSimilarity: ${similarity}%`; 31 | let captionImg = `Name: ${filename}\nEpisode: ${episode}\n\nSimilarity: ${similarity}%`; 32 | 33 | await conn.sendFile(m.chat, videoURL, filename, captionVid, m); 34 | await conn.sendFile(m.chat, videoIMG, filename, captionImg, m); 35 | } else { 36 | m.reply('No result found'); 37 | } 38 | } catch (error) { 39 | console.error(error); 40 | if (error.includes(`Kirim/Reply Gambar dengan caption ${usedPrefix + command}`)) { 41 | m.reply(error); 42 | } else { 43 | m.reply('Internal server error'); 44 | } 45 | } 46 | }; 47 | 48 | handler.help = ['animesearch'] 49 | handler.tags = ['anime'] 50 | handler.command = /^(animesearch)$/i 51 | 52 | handler.register = true 53 | handler.limit = false 54 | 55 | export default handler 56 | -------------------------------------------------------------------------------- /plugins/sticker-toimg.js: -------------------------------------------------------------------------------- 1 | import sharp from 'sharp' 2 | import { webp2png } from '../lib/webp2mp4.js' 3 | import fs from 'fs' 4 | 5 | let handler = async (m, { conn, usedPrefix, command }) => { 6 | const notStickerMessage = `Reply sticker dengan command *${usedPrefix + command}*`; 7 | 8 | if (!m.quoted) throw notStickerMessage; 9 | 10 | const q = m.quoted || m; 11 | const mime = q.mimetype || ''; 12 | 13 | if (!/image\/webp/.test(mime)) { 14 | try { 15 | const name = await conn.getName(m.sender); 16 | const media = await q.download(); 17 | const out = await webp2png(media).catch(_ => null) || Buffer.alloc(0); 18 | await conn.sendFile(m.chat, out, 'out.png', 'Request By ' + name, m); 19 | 20 | if (fs.existsSync(out || 'out.png' || './tmp/out.png' || `./tmp/${out}`)) { 21 | await fs.promises.unlink(out || 'out.png' || './tmp/out.png' || `./tmp/${out}`); 22 | } 23 | } catch (error) { 24 | console.error(error); 25 | m.reply(`Terjadi kesalahan: ${notStickerMessage}`); 26 | } 27 | } else { 28 | try { 29 | const media = await q.download(); 30 | 31 | 32 | 33 | await m.react('🕓') 34 | 35 | const decodedBuffer = await sharp(media).toFormat('png') 36 | .png({ quality: 100, progressive: true, compressionLevel: 9 }) 37 | .toBuffer(); 38 | 39 | if (decodedBuffer.length > 0) { 40 | await conn.sendFile(m.chat, decodedBuffer, 'out.png', '*DONE (≧ω≦)ゞ*', m); 41 | 42 | if (fs.existsSync('out.png' || './tmp/out.png')) { 43 | await fs.promises.unlink('out.png' || './tmp/out.png'); 44 | } 45 | } else { 46 | throw 'Gagal mengonversi stiker menjadi gambar.'; 47 | } 48 | } catch (error) { 49 | console.error(error); 50 | if (error.message.includes('Timeout')) { 51 | m.reply('Proses konversi terlalu lama. Silakan coba lagi.'); 52 | } else { 53 | m.reply(`Terjadi kesalahan: ${notStickerMessage}`); 54 | } 55 | } 56 | } 57 | }; 58 | 59 | handler.help = ['toimg (reply)'] 60 | handler.tags = ['maker'] 61 | handler.command = ['toimg'] 62 | 63 | handler.register = true 64 | handler.limit = true 65 | 66 | export default handler -------------------------------------------------------------------------------- /plugins/stalk-ff.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args }) => { 4 | const userId = args[0] 5 | 6 | if (!userId) throw 'Masukkan User ID' 7 | 8 | let { key } = await conn.sendMessage(m.chat, { 9 | text: "Sedang mengecek data akun...", 10 | }) 11 | 12 | try { 13 | let res = await axios.get(`${APIs.ryzumi}/api/stalk/freefire?userId=${userId}`) 14 | let result = res.data 15 | 16 | if (!result.name) throw 'API tidak mengembalikan data yang valid' 17 | 18 | let equippedItemsText = '' 19 | if (result.equippedItems && Array.isArray(result.equippedItems)) { 20 | equippedItemsText = result.equippedItems 21 | .map((item, index) => `${index + 1}. ${item.name}`) 22 | .join('\n') 23 | } 24 | 25 | let ini_text = ` 26 | *MAIN INFORMATIONS* 27 | > Name: ${result.name} 28 | > Bio: ${result.bio} 29 | > Like: ${result.like} 30 | > Level: ${result.level} 31 | > Exp: ${result.exp} 32 | > Region: ${result.region} 33 | > Honor Score: ${result.honorScore} 34 | > BR Rank: ${result.brRank} (${result.brRankPoint}) 35 | > CS Rank Point: ${result.csRankPoint} 36 | > Account Created: ${result.accountCreated} 37 | > Last Login: ${result.lastLogin} 38 | > Prefer Mode: ${result.preferMode} 39 | > Language: ${result.language} 40 | > Booyah Pass Level: ${result.booyahPassLevel} 41 | 42 | *PET INFORMATION* 43 | > Name: ${result.petInformation.name} 44 | > Level: ${result.petInformation.level} 45 | > Exp: ${result.petInformation.exp} 46 | > Star Marked: ${result.petInformation.starMarked} 47 | > Selected: ${result.petInformation.selected} 48 | 49 | *EQUIPPED ITEMS* 50 | ${equippedItemsText} 51 | ` 52 | 53 | await conn.sendMessage(m.chat, { 54 | text: ini_text, 55 | edit: key 56 | }) 57 | } catch (e) { 58 | await conn.sendMessage(m.chat, { 59 | text: `error from API: ${e}`, 60 | edit: key 61 | }) 62 | } 63 | } 64 | 65 | handler.help = ['ffstalk'] 66 | handler.tags = ['stalk'] 67 | handler.command = /^(stalkff|ffstalk)$/i 68 | 69 | handler.register = true 70 | handler.limit = true 71 | 72 | export default handler 73 | -------------------------------------------------------------------------------- /lib/webp2mp4.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import FormData from 'form-data'; 3 | import { JSDOM } from 'jsdom'; 4 | /** 5 | * 6 | * @param {Buffer|String} source 7 | */ 8 | 9 | async function webp2mp4(source) { 10 | let form = new FormData 11 | let isUrl = typeof source === 'string' && /https?:\/\//.test(source) 12 | form.append('new-image-url', isUrl ? source : '') 13 | form.append('new-image', isUrl ? '' : source, 'image.webp') 14 | let res = await fetch('https://ezgif.com/webp-to-mp4', { 15 | method: 'POST', 16 | body: form 17 | }) 18 | let html = await res.text() 19 | let { document } = new JSDOM(html).window 20 | let form2 = new FormData 21 | let obj = {} 22 | for (let input of document.querySelectorAll('form input[name]')) { 23 | obj[input.name] = input.value 24 | form2.append(input.name, input.value) 25 | } 26 | let res2 = await fetch('https://ezgif.com/webp-to-mp4/' + obj.file, { 27 | method: 'POST', 28 | body: form2 29 | }) 30 | let html2 = await res2.text() 31 | let { document: document2 } = new JSDOM(html2).window 32 | return new URL(document2.querySelector('div#output > p.outfile > video > source').src, res2.url).toString() 33 | } 34 | 35 | async function webp2png(source) { 36 | let form = new FormData 37 | let isUrl = typeof source === 'string' && /https?:\/\//.test(source) 38 | form.append('new-image-url', isUrl ? source : '') 39 | form.append('new-image', isUrl ? '' : source, 'image.webp') 40 | let res = await fetch('https://ezgif.com/webp-to-png', { 41 | method: 'POST', 42 | body: form 43 | }) 44 | let html = await res.text() 45 | let { document } = new JSDOM(html).window 46 | let form2 = new FormData 47 | let obj = {} 48 | for (let input of document.querySelectorAll('form input[name]')) { 49 | obj[input.name] = input.value 50 | form2.append(input.name, input.value) 51 | } 52 | let res2 = await fetch('https://ezgif.com/webp-to-png/' + obj.file, { 53 | method: 'POST', 54 | body: form2 55 | }) 56 | let html2 = await res2.text() 57 | let { document: document2 } = new JSDOM(html2).window 58 | return new URL(document2.querySelector('div#output > p.outfile > img').src, res2.url).toString() 59 | } 60 | 61 | export { 62 | webp2mp4, 63 | webp2png 64 | } 65 | -------------------------------------------------------------------------------- /plugins/owner-inspect.js: -------------------------------------------------------------------------------- 1 | import util from 'util' 2 | export const handler = async (m, { conn, usedPrefix, command }) => { 3 | try { 4 | const key = m.key || {} 5 | const msg = m.messages || m.message || {} 6 | 7 | const info = { 8 | chat: m.chat, 9 | isGroup: m.isGroup, 10 | fromMe: m.fromMe, 11 | sender: m.sender, 12 | pushName: m.pushName, 13 | name: m.name, 14 | key: { 15 | id: key.id, 16 | remoteJid: key.remoteJid, 17 | fromMe: key.fromMe, 18 | participant: key.participant, 19 | participantPn: key.participantPn || conn.decodeJid(key.participant) // fallback decode 20 | }, 21 | participant: m.participant, 22 | contextInfo_participant: msg?.extendedTextMessage?.contextInfo?.participant || msg?.conversation?.contextInfo?.participant, 23 | contextInfo_participantPn: msg?.extendedTextMessage?.contextInfo?.participantPn || msg?.conversation?.contextInfo?.participantPn, 24 | decodedSender: conn.decodeJid(m.sender), // tambahan: nomor hasil decode 25 | mtype: m.mtype, 26 | hasQuoted: !!m.quoted, 27 | quoted: m.quoted ? { 28 | id: m.quoted.id, 29 | chat: m.quoted.chat, 30 | sender: m.quoted.sender, 31 | participant: m.quoted.messages?.contextInfo?.participant, 32 | decodedQuotedSender: conn.decodeJid(m.quoted.sender) 33 | } : null, 34 | } 35 | 36 | const summary = [ 37 | `chat: ${info.chat}`, 38 | `isGroup: ${info.isGroup}`, 39 | `sender: ${info.sender}`, 40 | `decodedSender: ${info.decodedSender}`, 41 | `pushName: ${info.pushName}`, 42 | `mtype: ${info.mtype}`, 43 | `key.id: ${info.key.id}`, 44 | `key.participant: ${info.key.participant}`, 45 | `key.participantPn: ${info.key.participantPn}`, 46 | `participant: ${info.participant}`, 47 | ].join('\n') 48 | 49 | const inspected = util.inspect(info, { depth: 3, colors: false, compact: false, maxArrayLength: 50 }) 50 | await m.reply(`${summary}\n\n--- detail ---\n${inspected}`) 51 | } catch (e) { 52 | await m.reply(`Error: ${e && e.stack ? e.stack : e}`) 53 | } 54 | } 55 | 56 | handler.command = /^(inspect|props|probe)$/i 57 | handler.owner = false 58 | 59 | export default handler 60 | -------------------------------------------------------------------------------- /plugins/group-info.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | let handler = async (m, { conn, participants, groupMetadata }) => { 4 | const ppUrls = [ 5 | 'https://i.ibb.co/VVXTRv0/f8323e88975b4e8c15580fbb8daed698.jpg', 6 | 'https://i.ibb.co/mvt0NPZ/31889221389613dd440c9909cd27771a.jpg', 7 | 'https://i.ibb.co/jhCy322/f272360445283d8385c35afa697bdf43.jpg', 8 | ]; 9 | let ppUrl = await conn.profilePictureUrl(m.chat, 'image').catch(_ => null); 10 | 11 | if (!ppUrl) { 12 | ppUrl = ppUrls[Math.floor(Math.random() * ppUrls.length)]; 13 | } 14 | 15 | const ppBuffer = await axios.get(ppUrl, { responseType: 'arraybuffer' }).then(res => res.data).catch(_ => null); 16 | 17 | const { isBanned, welcome, detect, sWelcome, sBye, sPromote, sDemote, antiLink, delete: del } = global.db.data.chats[m.chat]; 18 | const groupAdmins = participants.filter(p => p.admin); 19 | const listAdmin = groupAdmins.map((v, i) => `${i + 1}. @${v.id.split('@')[0]}`).join('\n'); 20 | const owner = groupMetadata.owner || groupAdmins.find(p => p.admin === 'superadmin')?.id || m.chat.split`-`[0] + '@s.whatsapp.net'; 21 | let text = `*「 Group Information 」*\n 22 | *ID:* 23 | ${groupMetadata.id} 24 | *Name:* 25 | ${groupMetadata.subject} 26 | *Description:* 27 | ${groupMetadata.desc?.toString() || 'unknown'} 28 | *Total Members:* 29 | ${participants.length} Members 30 | *Group Owner:* 31 | @${owner.split('@')[0]} 32 | *Group Admins:* 33 | ${listAdmin} 34 | *Group Settings:* 35 | ${isBanned ? '✅' : '❌'} Banned 36 | ${welcome ? '✅' : '❌'} Welcome 37 | ${detect ? '✅' : '❌'} Detect 38 | ${del ? '❌' : '✅'} Anti Delete 39 | ${antiLink ? '✅' : '❌'} Anti Link 40 | *Message Settings:* 41 | Welcome: ${sWelcome} 42 | Bye: ${sBye} 43 | Promote: ${sPromote} 44 | Demote: ${sDemote} 45 | `.trim(); 46 | 47 | if (ppBuffer) { 48 | conn.sendFile(m.chat, Buffer.from(ppBuffer), 'pp.jpg', text, m, false, { mentions: [...groupAdmins.map(v => v.id), owner] }); 49 | } else { 50 | conn.reply(m.chat, text, m, false, { mentions: [...groupAdmins.map(v => v.id), owner] }); 51 | } 52 | } 53 | 54 | handler.help = ['infogrup']; 55 | handler.tags = ['group']; 56 | handler.command = /^(gro?upinfo|info(gro?up|gc))$/i; 57 | 58 | handler.group = true; 59 | 60 | export default handler; 61 | -------------------------------------------------------------------------------- /plugins/group-add.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | 3 | let handler = async (m, { conn, text, participants, usedPrefix, command }) => { 4 | if (!text) throw `_Masukan nomor!_\nContoh:\n\n${usedPrefix + command} ${global.owner[0]}`; 5 | 6 | m.reply('_Sedang di proses..._'); 7 | const _participants = participants.map(user => user.id); 8 | 9 | const users = await Promise.all( 10 | text.split(',') 11 | .map(v => v.replace(/[^0-9]/g, '')) 12 | .filter(v => v.length > 4 && v.length < 20 && !_participants.includes(v + '@s.whatsapp.net')) 13 | .map(async v => { 14 | const userCheck = await conn.onWhatsApp(v + '@s.whatsapp.net'); 15 | return userCheck[0]?.exists ? v + '@c.us' : null; 16 | }) 17 | ).then(results => results.filter(Boolean)); 18 | 19 | const response = await conn.groupParticipantsUpdate(m.chat, users, "add"); 20 | 21 | const pp = await conn.profilePictureUrl(m.chat, 'image').catch(() => null); 22 | const jpegThumbnail = pp ? Buffer.from(await (await fetch(pp)).arrayBuffer()) : Buffer.alloc(0); 23 | 24 | for (const participant of response) { 25 | const jid = participant.content.attrs.phone_number; 26 | const status = participant.status; 27 | 28 | if (status === '408') { 29 | conn.reply(m.chat, `Tidak dapat menambahkan @${jid.split('@')[0]}!\nMungkin @${jid.split('@')[0]} baru keluar dari grup ini atau dikick`, m); 30 | } else if (status === '403') { 31 | const inviteCode = participant.content.content[0].attrs.code; 32 | const inviteExp = participant.content.content[0].attrs.expiration; 33 | await m.reply(`Mengundang @${jid.split('@')[0]} menggunakan invite...`); 34 | 35 | await conn.sendGroupV4Invite( 36 | m.chat, 37 | jid, 38 | inviteCode, 39 | inviteExp, 40 | await conn.getName(m.chat), 41 | 'Undangan untuk bergabung ke grup WhatsApp saya', 42 | jpegThumbnail 43 | ); 44 | } 45 | } 46 | }; 47 | 48 | handler.help = ['add', '+'].map(v => v + ' @user'); 49 | handler.tags = ['group']; 50 | handler.command = /^(add|\+)$/i; 51 | handler.admin = true; 52 | handler.group = true; 53 | handler.botAdmin = true; 54 | handler.fail = null; 55 | 56 | export default handler; 57 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import yargs from 'yargs'; 2 | import cfonts from 'cfonts'; 3 | import { fileURLToPath } from 'url'; 4 | import { join, dirname } from 'path'; 5 | import { createRequire } from 'module'; 6 | import { createInterface } from 'readline'; 7 | import { setupMaster, fork } from 'cluster'; 8 | import { watchFile, unwatchFile } from 'fs'; 9 | 10 | // Setup console output 11 | const { say } = cfonts; 12 | const rl = createInterface(process.stdin, process.stdout); 13 | const __dirname = dirname(fileURLToPath(import.meta.url)); 14 | const require = createRequire(__dirname); 15 | const { name, author } = require(join(__dirname, './package.json')); 16 | 17 | say('Lightweight\nWhatsApp Bot', { font: 'chrome', align: 'center', gradient: ['red', 'magenta'] }); 18 | say(`'${name}' By @${author.name || author}`, { font: 'console', align: 'center', gradient: ['red', 'magenta'] }); 19 | 20 | console.log('🐾 Starting...'); 21 | 22 | var isRunning = false; 23 | 24 | /** 25 | * Start a js file 26 | * @param {String} file `path/to/file` 27 | */ 28 | function start(file) { 29 | if (isRunning) return; 30 | isRunning = true; 31 | 32 | let args = [join(__dirname, file), ...process.argv.slice(2)]; 33 | say([process.argv[0], ...args].join(' '), { font: 'console', align: 'center', gradient: ['red', 'magenta'] }); 34 | 35 | setupMaster({ exec: args[0], args: args.slice(1) }); 36 | let p = fork(); 37 | 38 | p.on('message', data => { 39 | console.log('[✅RECEIVED]', data); 40 | switch (data) { 41 | case 'reset': 42 | p.kill(); // Change here 43 | isRunning = false; 44 | start(file); 45 | break; 46 | case 'uptime': 47 | p.send(process.uptime()); 48 | break; 49 | default: 50 | console.warn('[⚠️ UNRECOGNIZED MESSAGE]', data); 51 | } 52 | }); 53 | 54 | p.on('exit', (_, code) => { 55 | isRunning = false; 56 | console.error('[❗] Exited with code:', code); 57 | if (code !== 0) { 58 | console.log('[🔄 Restarting worker due to non-zero exit code...'); 59 | return start(file); 60 | } 61 | 62 | watchFile(args[0], () => { 63 | unwatchFile(args[0]); 64 | start(file); 65 | }); 66 | }); 67 | 68 | let opts = yargs(process.argv.slice(2)).exitProcess(false).parse(); 69 | 70 | if (!opts['test']) { 71 | if (!rl.listenerCount()) { 72 | rl.on('line', line => { 73 | p.emit('message', line.trim()); 74 | }); 75 | } 76 | } 77 | } 78 | 79 | start('main.js'); 80 | -------------------------------------------------------------------------------- /plugins/image-faketweet.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { uploadPomf } from '../lib/uploadImage.js' 3 | 4 | const handler = async (m, { conn, args, usedPrefix, command }) => { 5 | if (args.length < 1 && !(m.quoted && m.quoted.text)) { 6 | throw `Gunakan format: ${usedPrefix || '.'}${command} ||\n\nContoh:\n${usedPrefix || '.'}${command} Ryzumi|ryzumi_starlette|Halo, ini adalah tweet!!`; 7 | } 8 | 9 | let [nameArg, usernameArg, tweetArg] = args.join(' ').split('|'); 10 | 11 | // Fallbacks 12 | const displayName = nameArg?.trim() || (await conn.getName(m.sender)); 13 | const username = (usernameArg?.trim()) || displayName.replace(/\s+/g, '_').toLowerCase(); 14 | let tweet = (tweetArg && tweetArg.trim()) || (m.quoted && m.quoted.text) || ''; 15 | if (!tweet) throw `Teks tweet kosong. Tuliskan setelah tanda | atau reply teks.`; 16 | 17 | // Avatar otomatis 18 | const avatar = await conn.profilePictureUrl(m.sender, 'image').catch(_ => './src/avatar_contact.png'); 19 | 20 | // Cek apakah ada gambar 21 | let imageUrl = ''; 22 | try { 23 | const q = m.quoted ? m.quoted : m; 24 | const mime = (q.msg || q).mimetype || ''; 25 | if (/^image\//i.test(mime)) { 26 | const media = await q.download(); 27 | imageUrl = await uploadPomf(media); 28 | } 29 | } catch (e) { 30 | m.reply('_Gagal mengambil gambar_'); 31 | } 32 | 33 | // Random metrics 34 | const rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; 35 | const retweets = rand(200, 1000); 36 | const comment = rand(200, 1000); 37 | const likes = rand(500, 2000); 38 | 39 | // Build URL 40 | const base = `${APIs.ryzumi}/api/image/faketweet`; 41 | const params = new URLSearchParams(); 42 | params.set('bg', 'dim'); 43 | params.set('avatar', avatar); 44 | params.set('name', displayName); 45 | params.set('username', username); 46 | params.set('tweet', tweet); 47 | params.set('retweets', String(retweets)); 48 | params.set('comment', String(comment)); 49 | params.set('likes', String(likes)); 50 | params.set('verified', 'true'); 51 | if (imageUrl) params.set('image', imageUrl); 52 | 53 | const url = `${base}?${params.toString()}`; 54 | 55 | const response = await axios.get(url, { responseType: 'arraybuffer' }); 56 | const buffer = Buffer.from(response.data); 57 | await conn.sendFile(m.chat, buffer, 'faketweet.png', '', m); 58 | } 59 | 60 | handler.help = ['faketweet'] 61 | handler.tags = ['maker'] 62 | handler.command = /^(faketweet)$/i 63 | 64 | handler.register = true 65 | 66 | export default handler 67 | -------------------------------------------------------------------------------- /plugins/ai-openai.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | const handler = async (m, { text, conn }) => { 5 | try { 6 | if (!text && !m.quoted && !m.mtype.includes('imageMessage')) { 7 | throw "Masukkan pertanyaan atau kirim gambar untuk deskripsi!\n\n*Contoh:* Siapa presiden Indonesia?"; 8 | } 9 | 10 | let imgUrl = null 11 | 12 | if (m.quoted && m.quoted.mtype === 'imageMessage') { 13 | let img = await m.quoted.download() 14 | if (img) { 15 | img = Buffer.from(img) 16 | let link = await ryzenCDN(img) 17 | if (!link) throw 'Gagal mengupload gambar' 18 | imgUrl = typeof link === 'object' ? link.url : link 19 | } 20 | } else if (m.mtype.includes('imageMessage')) { 21 | let img = await m.download() 22 | if (img) { 23 | img = Buffer.from(img) 24 | let link = await ryzenCDN(img) 25 | if (!link) throw 'Gagal mengupload gambar' 26 | imgUrl = typeof link === 'object' ? link.url : link 27 | } 28 | } 29 | 30 | let anu = 'Ubah Namamu menjadi Ryzumi Starlette, dan kamu adalah wanita paling cantik, penyayang, riang, namun tsundere. dan kamu adalah pacarku.' 31 | let apiUrl 32 | 33 | if (imgUrl) { 34 | apiUrl = `${APIs.ryzumi}/api/ai/v2/chatgpt?text=${encodeURIComponent(text || '')}&prompt=${encodeURIComponent(anu)}&imageUrl=${encodeURIComponent(imgUrl)}&session=chatgpt-${encodeURIComponent(global.namebot)}-${encodeURIComponent(m.sender)}` 35 | } else if (text) { 36 | apiUrl = `${APIs.ryzumi}/api/ai/v2/chatgpt?text=${encodeURIComponent(text)}&prompt=${encodeURIComponent(anu)}&session=chatgpt-${encodeURIComponent(global.namebot)}-${encodeURIComponent(m.sender)}` 37 | } else { 38 | throw "Tidak ada teks atau gambar yang valid untuk diproses." 39 | } 40 | 41 | let hasil = await fetch(apiUrl) 42 | if (!hasil.ok) throw new Error("Request ke API gagal: " + hasil.statusText) 43 | 44 | let result = await hasil.json() 45 | let responseMessage = result.result || "Tidak ada respons dari AI." 46 | 47 | await conn.sendMessage(m.chat, { text: responseMessage }) 48 | 49 | } catch (error) { 50 | console.error('Error in handler:', error) 51 | await conn.sendMessage(m.chat, { text: `Error: Mana textnya njir?` }) 52 | } 53 | } 54 | 55 | handler.help = ['gpt'] 56 | handler.tags = ['ai'] 57 | handler.command = /^(gpt)$/i 58 | 59 | handler.limit = 6 60 | handler.premium = false 61 | handler.register = true 62 | 63 | export default handler 64 | -------------------------------------------------------------------------------- /plugins/downloader-twitter.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args }) => { 4 | if (!args[0]) throw 'Please provide a Twitter URL'; 5 | const sender = m.sender.split('@')[0]; 6 | const url = args[0]; 7 | 8 | 9 | 10 | 11 | await m.react('🕓') 12 | 13 | try { 14 | let downloadResult = (await axios.get(`${APIs.ryzumi}/api/downloader/twitter?url=${url}`)).data; 15 | 16 | if (!downloadResult.status || !downloadResult.media || downloadResult.media.length === 0) { 17 | const tempResult = (await axios.get(`${APIs.ryzumi}/api/downloader/v2/twitter?url=${url}`)).data; 18 | downloadResult = Array.isArray(tempResult) && tempResult.length > 0 19 | ? { status: true, media: tempResult } 20 | : { status: false, media: [] }; 21 | } 22 | 23 | if (!downloadResult.status || !downloadResult.media || downloadResult.media.length === 0) { 24 | throw 'Gagal mendownload konten dari Twitter'; 25 | } 26 | 27 | const type = downloadResult.type || 'video'; 28 | 29 | if (type === 'image') { 30 | for (let i = 0; i < downloadResult.media.length; i++) { 31 | const mediaUrl = downloadResult.media[i]; 32 | const { data: imageBuffer } = await axios.get(mediaUrl, { responseType: 'arraybuffer' }); 33 | const caption = i === 0 ? `Ini kak fotonya @${sender}` : ''; 34 | await conn.sendMessage( 35 | m.chat, 36 | { 37 | image: imageBuffer, 38 | caption: caption, 39 | fileName: `image_${i + 1}.jpg`, 40 | mentions: i === 0 ? [m.sender] : [], 41 | }, 42 | { quoted: m } 43 | ); 44 | } 45 | } else { 46 | const mediaUrl = downloadResult.media[0].url || downloadResult.media[0]; 47 | const { data: videoBuffer } = await axios.get(mediaUrl, { responseType: 'arraybuffer' }); 48 | const caption = `Ini kak videonya @${sender}`; 49 | await conn.sendMessage( 50 | m.chat, 51 | { 52 | video: videoBuffer, 53 | mimetype: 'video/mp4', 54 | fileName: 'video.mp4', 55 | caption: caption, 56 | mentions: [m.sender], 57 | }, 58 | { quoted: m } 59 | ); 60 | } 61 | } catch (error) { 62 | console.error('Handler Error:', error); 63 | conn.reply(m.chat, `An error occurred: ${error}`, m); 64 | } 65 | }; 66 | 67 | handler.help = ['twitter ']; 68 | handler.tags = ['downloader']; 69 | handler.command = /^(x|twt|twitter(dl)?)$/i; 70 | 71 | handler.limit = true 72 | handler.register = true 73 | 74 | export default handler 75 | -------------------------------------------------------------------------------- /plugins/expired-set.js: -------------------------------------------------------------------------------- 1 | // perintah digunakan ketika grup sudah join, jika sudah join ketikan .addsewa 2 | // Xnuvers007 3 | 4 | let handler = async (m, { conn, args, usedPrefix, command }) => { 5 | if (!args[0] || (!/\d+/.test(args[0]) && !/[dhm]/.test(args[0]))) { 6 | throw `Masukkan angka mewakili jumlah waktu!\nMisal: ${usedPrefix + command} 30m`; 7 | } 8 | 9 | let who; 10 | if (m.isGroup) who = args[1] ? args[1] : m.chat; 11 | else who = args[1]; 12 | 13 | let match = args[0].match(/(\d+)([dhm])/); 14 | if (!match) throw 'Format waktu tidak valid. Gunakan "d" untuk hari, "h" untuk jam, atau "m" untuk menit. Contoh: 30m, 1h, 2d.'; 15 | 16 | let timeValue = parseInt(match[1]); 17 | let timeUnit = match[2].toLowerCase(); 18 | 19 | let milliseconds; 20 | switch (timeUnit) { 21 | case 'd': 22 | milliseconds = timeValue * 24 * 60 * 60 * 1000; 23 | break; 24 | case 'h': 25 | milliseconds = timeValue * 60 * 60 * 1000; 26 | break; 27 | case 'm': 28 | milliseconds = timeValue * 60 * 1000; 29 | break; 30 | default: 31 | throw 'Waktu tidak valid. Gunakan "d" untuk hari, "h" untuk jam, atau "m" untuk menit.'; 32 | } 33 | 34 | var now = new Date() * 1; 35 | if (now < global.db.data.chats[who].expired) global.db.data.chats[who].expired = milliseconds; 36 | else global.db.data.chats[who].expired = now + milliseconds; 37 | 38 | let timeUnitText; 39 | switch (timeUnit) { 40 | case 'd': 41 | timeUnitText = 'hari'; 42 | break; 43 | case 'h': 44 | timeUnitText = 'jam'; 45 | break; 46 | case 'm': 47 | timeUnitText = 'menit'; 48 | break; 49 | } 50 | 51 | conn.reply(m.chat, `Berhasil menetapkan hari kadaluarsa untuk Grup ini selama ${args[0]} ${timeUnitText}.\n\nHitung Mundur: ${msToDate(global.db.data.chats[who].expired - now)}`, m); 52 | } 53 | 54 | handler.help = ['addsewa '] 55 | handler.tags = ['owner'] 56 | handler.command = /^(setexpired|addsewa|tambahsewa|nyewa)$/i 57 | handler.rowner = true 58 | handler.group = true 59 | 60 | export default handler 61 | 62 | function msToDate(ms) { 63 | let days = Math.floor(ms / (24 * 60 * 60 * 1000)); 64 | let daysms = ms % (24 * 60 * 60 * 1000); 65 | let hours = Math.floor((daysms) / (60 * 60 * 1000)); 66 | let hoursms = ms % (60 * 60 * 1000); 67 | let minutes = Math.floor((hoursms) / (60 * 1000)); 68 | return days + " hari " + hours + " jam " + minutes + " menit"; 69 | } 70 | -------------------------------------------------------------------------------- /plugins/youtube-yta.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import fs from 'fs' 3 | import path from 'path' 4 | import { pipeline } from 'stream' 5 | import { promisify } from 'util' 6 | 7 | const streamPipeline = promisify(pipeline) 8 | 9 | let handler = async (m, { conn, command, text, usedPrefix }) => { 10 | if (!text) throw `Usage: ${usedPrefix}${command} ` 11 | 12 | await m.react('🕓') 13 | 14 | const videoUrl = text 15 | const apiUrl = `${APIs.ryzumi}/api/downloader/ytmp3?url=${encodeURIComponent(videoUrl)}` 16 | 17 | try { 18 | const response = await axios.get(apiUrl) 19 | const data = response.data 20 | 21 | if (!data.url) throw new Error('Audio URL not found in API response.') 22 | 23 | const { title, author, lengthSeconds, views, uploadDate, videoUrl, thumbnail } = data 24 | const safeTitle = title.replace(/[\\/:*?"<>|]/g, '').slice(0, 50) 25 | const tmpDir = path.join(process.cwd(), 'tmp') 26 | 27 | if (!fs.existsSync(tmpDir)) { 28 | fs.mkdirSync(tmpDir, { recursive: true }) 29 | } 30 | 31 | const filePath = path.join(tmpDir, `${safeTitle}.mp3`) 32 | 33 | // Download audio file 34 | const audioResponse = await axios({ 35 | method: 'get', 36 | url: data.url, 37 | responseType: 'stream' 38 | }) 39 | 40 | await streamPipeline(audioResponse.data, fs.createWriteStream(filePath)) 41 | 42 | const caption = `Ini kak audionya @${m.sender.split('@')[0]} 43 | 44 | *Title*: ${title} 45 | *Author*: ${author} 46 | *Duration*: ${lengthSeconds} sec 47 | *Views*: ${views} 48 | *Uploaded*: ${uploadDate} 49 | *URL*: ${videoUrl}` 50 | 51 | // Kirim file audio sebagai dokumen 52 | await conn.sendMessage(m.chat, { 53 | document: { url: filePath }, 54 | mimetype: 'audio/mpeg', 55 | fileName: `${safeTitle}.mp3`, 56 | caption, 57 | contextInfo: { 58 | externalAdReply: { 59 | //showAdAttribution: true, 60 | mediaType: 2, 61 | mediaUrl: videoUrl, 62 | title: title, 63 | body: 'Audio Download', 64 | sourceUrl: videoUrl, 65 | thumbnail: await (await conn.getFile(thumbnail)).data, 66 | }, 67 | }, 68 | }, { quoted: m }) 69 | 70 | fs.unlink(filePath, () => { }) 71 | 72 | } catch (error) { 73 | console.error('Error:', error.message) 74 | throw `Gagal: ${error.message}` 75 | } 76 | } 77 | 78 | handler.help = ['ytmp3'].map(v => v + ' ') 79 | handler.tags = ['downloader'] 80 | handler.command = /^(ytmp3)$/i 81 | 82 | handler.limit = 10 83 | handler.register = true 84 | handler.disable = false 85 | 86 | export default handler 87 | -------------------------------------------------------------------------------- /plugins/ai-gemini.js: -------------------------------------------------------------------------------- 1 | import fetch from "node-fetch" 2 | import { ryzenCDN } from '../lib/uploadFile.js' 3 | 4 | const handler = async (m, { text, usedPrefix, command, conn }) => { 5 | try { 6 | if (!text && !m.quoted && !m.mtype.includes('imageMessage')) { 7 | throw "Masukkan pertanyaan atau kirim gambar untuk deskripsi!\n\n*Contoh:* Siapa presiden Indonesia?"; 8 | } 9 | 10 | let imgUrl = null; 11 | 12 | if (m.quoted && m.quoted.mtype === 'imageMessage') { 13 | let img = await m.quoted.download(); 14 | if (img) { 15 | img = Buffer.from(img); 16 | let link = await ryzenCDN(img); 17 | if (!link) throw 'Gagal mengupload gambar'; 18 | imgUrl = typeof link === 'object' ? link.url : link; 19 | } 20 | } else if (m.mtype.includes('imageMessage')) { 21 | let img = await m.download(); 22 | if (img) { 23 | img = Buffer.from(img); 24 | let link = await ryzenCDN(img); 25 | if (!link) throw 'Gagal mengupload gambar'; 26 | imgUrl = typeof link === 'object' ? link.url : link; 27 | } 28 | } 29 | 30 | let anu = 'Ubah Namamu menjadi Ryzumi Starlette, dan kamu adalah wanita paling cantik, penyayang, riang, namun tsundere. dan kamu adalah pacarku.' 31 | let apiUrl; 32 | if (imgUrl) { 33 | apiUrl = `${APIs.ryzumi}/api/ai/gemini?text=${encodeURIComponent(text)}&prompt=${encodeURIComponent(anu)}&url=${encodeURIComponent(imgUrl)}&session=gemini-${encodeURIComponent(global.namebot)}-${encodeURIComponent(m.sender)}`; 34 | } else if (text) { 35 | apiUrl = `${APIs.ryzumi}/api/ai/gemini?text=${encodeURIComponent(text)}&prompt=${encodeURIComponent(anu)}&session=gemini-${encodeURIComponent(global.namebot)}-${encodeURIComponent(m.sender)}`; 36 | } else { 37 | throw "Tidak ada teks atau gambar yang valid untuk diproses."; 38 | } 39 | 40 | let hasil = await fetch(apiUrl); 41 | if (!hasil.ok) throw new Error("Request ke API gagal: " + hasil.statusText); 42 | 43 | let result = await hasil.json(); 44 | if (!result.success) throw new Error("Response API tidak berhasil"); 45 | 46 | let responseMessage = result.result || "Tidak ada respons dari AI."; 47 | 48 | await conn.sendMessage(m.chat, { text: responseMessage }); 49 | 50 | } catch (error) { 51 | console.error('Error in handler:', error); 52 | await conn.sendMessage(m.chat, { text: `Error: Mana textnya njir?` }); 53 | } 54 | } 55 | 56 | handler.help = ['gemini'] 57 | handler.tags = ['ai'] 58 | handler.command = /^(gemini)$/i 59 | 60 | handler.limit = 8 61 | handler.premium = false 62 | handler.register = true 63 | 64 | export default handler 65 | -------------------------------------------------------------------------------- /plugins/tool-cekpajak-bapenda.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args }) => { 4 | const platInput = args.join(' ') || args[0] || '' 5 | if (!platInput) throw 'Masukkan nomor plat. Contoh: `.cekpajak T1234CD` atau `.cekpajak T 1234 CD`' 6 | 7 | await m.react('🕓') 8 | 9 | try { 10 | const url = `${APIs.ryzumi}/api/tool/cek-pajak/bapenda?plat=${encodeURIComponent(platInput)}` 11 | 12 | const res = await axios.get(url) 13 | const result = res.data 14 | 15 | if (!result || !result.success) { 16 | const msg = result && result.message ? `Gagal: ${result.message}` : 'Gagal mengambil data pajak.' 17 | return await conn.sendMessage(m.chat, { text: msg }) 18 | } 19 | 20 | const d = result.data 21 | const info = d['informasi-umum'] || {} 22 | const pkb = d['pembayaran-pkb-pnbp'] || {} 23 | const pkbNon = d['pembayaran-pkb-pnbp-non-program'] || {} 24 | const pkbInfo = d['informasi-pkb-pnbp'] || {} 25 | 26 | const out = ` 27 | 📄 *CEK PAJAK BAPENDA* 28 | 29 | • Nomor Polisi : ${info['nomor-polisi'] || '-'} 30 | • Merk / Model : ${info['merk'] || '-'} / ${info['model'] || '-'} 31 | • Warna : ${info['warna'] || '-'} 32 | • Jenis : ${info['jenis'] || '-'} 33 | • Tahun Buat : ${info['tahun-buatan'] || '-'} 34 | 35 | 🧾 *Informasi PKB / STNK* 36 | • Periode : ${pkbInfo['dari'] || '-'} → ${pkbInfo['ke'] || '-'} 37 | • Tgl Pajak : ${pkbInfo['tanggal-pajak'] || '-'} 38 | • Tgl STNK : ${pkbInfo['tanggal-stnk'] || '-'} 39 | • Wilayah : ${pkbInfo['wilayah'] || '-'} 40 | 41 | 💸 *Pembayaran (Program)* 42 | • PKB Pokok : ${pkb['pkb-pokok'] ?? '-'} 43 | • Opsi PKB : ${pkb['opsen-pkb-pokok'] ?? '-'} 44 | • SWDKLLJ : ${pkb['swdkllj-pokok'] ?? '-'} 45 | • Total : ${pkb['total'] ?? '-'} 46 | 47 | 💸 *Pembayaran (Non-Program)* 48 | • PKB Pokok : ${pkbNon['pkb-pokok'] ?? '-'} 49 | • Opsi PKB : ${pkbNon['opsen-pkb-pokok'] ?? '-'} 50 | • SWDKLLJ : ${pkbNon['swdkllj-pokok'] ?? '-'} 51 | • Total : ${pkbNon['total'] ?? '-'} 52 | 53 | ⏱️ Diproses : ${d['tanggal-proses'] || '-'} 54 | ✔️ Bisa dibayar : ${d['canBePaid'] ? 'Ya' : 'Tidak'} 55 | `.trim() 56 | 57 | await conn.sendMessage(m.chat, { text: out }) 58 | 59 | } catch (e) { 60 | await conn.sendMessage(m.chat, { 61 | text: `Gagal mengambil data pajak.\n\nError: ${e.message || e}` 62 | }) 63 | } 64 | } 65 | 66 | handler.help = ['cekpajak [Plat]'] 67 | handler.tags = ['tool'] 68 | handler.command = /^(cekpajak|bapenda)$/i 69 | 70 | handler.register = true 71 | handler.limit = true 72 | 73 | export default handler 74 | -------------------------------------------------------------------------------- /plugins/downloader-sfile.js: -------------------------------------------------------------------------------- 1 | import * as cheerio from 'cheerio' 2 | import fetch from 'node-fetch' 3 | 4 | let handler = async (m, { conn, text }) => { 5 | if (text.match(/(https:\/\/sfile.mobi\/)/gi)) { 6 | let res = await download(text) 7 | if (!res) throw 'Tidak Dapat Mengunduh File' 8 | await m.reply(Object.keys(res).map(v => `*• ${v.capitalize()}:* ${res[v]}`).join('\n') + '\n\n_Sending file..._') 9 | const buff = Buffer.from(await (await fetch(res.download)).arrayBuffer()); 10 | conn.sendMessage(m.chat, { 11 | document: buff, 12 | fileName: res.filename, 13 | mimetype: res.mimetype 14 | }, { 15 | quoted: m 16 | }) 17 | } else if (text) { 18 | let [query, page] = text.split`|` 19 | let res = await search(query, page) 20 | if (!res.length) throw `Query "${text}" not found :/` 21 | res = res.map((v) => `*Title:* ${v.title}\n*Size:* ${v.size}\n*Link:* ${v.link}`).join`\n\n` 22 | m.reply(res) 23 | } else return m.reply('Input Query / Sfile Url!') 24 | } 25 | handler.help = ['sfile'] 26 | handler.tags = ['downloader'] 27 | handler.command = /^(sfile)$/i 28 | handler.limit = true 29 | 30 | export default handler 31 | 32 | async function search(query, page = 1) { 33 | let res = await fetch(`https://sfile.mobi/search.php?q=${query}&page=${page}`) 34 | let $ = cheerio.load(await res.text()) 35 | let result = [] 36 | $('div.list').each(function() { 37 | let title = $(this).find('a').text() 38 | let size = $(this).text().trim().split('(')[1] 39 | let link = $(this).find('a').attr('href') 40 | if (link) result.push({ 41 | title, 42 | size: size.replace(')', ''), 43 | link 44 | }) 45 | }) 46 | return result 47 | } 48 | 49 | async function download(url) { 50 | let res = await fetch(url) 51 | let $ = cheerio.load(await res.text()) 52 | let filename = $('img.intro').attr('alt') 53 | let mimetype = $('div.list').text().split(' - ')[1].split('\n')[0] 54 | let dl = $('#download').attr('href') 55 | let up_at = $('.list').eq(2).text().split(':')[1].trim() 56 | let uploader = $('.list').eq(1).find('a').eq(0).text().trim() 57 | let total_down = $('.list').eq(3).text().split(':')[1].trim() 58 | 59 | let data = await fetch(dl) 60 | let $$ = cheerio.load(await data.text()) 61 | let anu = $$('script').text() 62 | let download = anu.split('sf = "')[1].split('"')[0].replace(/\\/g, ''); 63 | 64 | return { 65 | filename, 66 | mimetype, 67 | upload_at: up_at, 68 | uploader, 69 | total_download: total_down, 70 | download 71 | } 72 | } -------------------------------------------------------------------------------- /plugins/youtube-play.js: -------------------------------------------------------------------------------- 1 | import yts from 'yt-search' 2 | import fs from 'fs' 3 | import path from 'path' 4 | import axios from 'axios' 5 | import { pipeline } from 'stream' 6 | import { promisify } from 'util' 7 | 8 | const streamPipeline = promisify(pipeline) 9 | 10 | const handler = async (m, { conn, command, text, usedPrefix }) => { 11 | if (!text) throw `Use example: ${usedPrefix}${command} ` 12 | 13 | const search = await yts(text) 14 | const vid = search.videos[Math.floor(Math.random() * search.videos.length)] 15 | if (!vid) throw 'Video not found, coba judul lain ya Sayang~' 16 | 17 | const { title, thumbnail, timestamp, views, ago, url } = vid 18 | 19 | await conn.sendMessage(m.chat, { 20 | image: { url: thumbnail }, 21 | caption: `🔍 Menemukan lagu: *${title}*\nSedang diunduh ya...`, 22 | }, { quoted: m }) 23 | 24 | try { 25 | const response = await axios.get(`${APIs.ryzumi}/api/downloader/ytmp3?url=${encodeURIComponent(url)}`) 26 | const data = response.data 27 | 28 | if (!data.url) throw new Error('Audio URL not found') 29 | 30 | const safeTitle = data.title.replace(/[\\/:*?"<>|]/g, '').slice(0, 50) 31 | const tmpDir = path.join(process.cwd(), 'tmp') 32 | 33 | if (!fs.existsSync(tmpDir)) { 34 | fs.mkdirSync(tmpDir, { recursive: true }) 35 | } 36 | 37 | const filePath = path.join(tmpDir, `${safeTitle}.mp3`) 38 | 39 | const audioResponse = await axios({ 40 | method: 'get', 41 | url: data.url, 42 | responseType: 'stream', 43 | }) 44 | 45 | await streamPipeline(audioResponse.data, fs.createWriteStream(filePath)) 46 | 47 | await conn.sendMessage(m.chat, { 48 | audio: { url: filePath }, 49 | mimetype: 'audio/mpeg', 50 | fileName: `${safeTitle}.mp3`, 51 | caption: `*${data.title}*\n*Duration*: ${data.lengthSeconds} sec\n*Views*: ${data.views}\n*Uploaded*: ${data.uploadDate}`, 52 | contextInfo: { 53 | externalAdReply: { 54 | //showAdAttribution: true, 55 | mediaType: 2, 56 | mediaUrl: data.videoUrl, 57 | title: data.title, 58 | body: 'Audio Download', 59 | sourceUrl: data.videoUrl, 60 | thumbnail: await (await conn.getFile(data.thumbnail)).data, 61 | }, 62 | }, 63 | }, { quoted: m }) 64 | 65 | fs.unlink(filePath, () => { }) 66 | 67 | } catch (error) { 68 | console.error('Error:', error.message) 69 | throw `Gagal download audionya Sayang 😢: ${error.message}` 70 | } 71 | } 72 | 73 | handler.help = ['play'].map(v => v + ' ') 74 | handler.tags = ['downloader'] 75 | handler.command = /^(play)$/i 76 | 77 | handler.limit = 8 78 | handler.register = true 79 | handler.disable = false 80 | 81 | export default handler 82 | -------------------------------------------------------------------------------- /plugins/downloader-spotify.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | let handler = async (m, { conn, args, usedPrefix, command }) => { 4 | if (!args[0]) throw `Usage: ${usedPrefix + command} ` 5 | 6 | await m.react('🕓') 7 | 8 | try { 9 | let response = await axios.get(`${APIs.ryzumi}/api/downloader/spotify?url=${encodeURIComponent(args[0])}`) 10 | let data = response.data 11 | 12 | if (data.success) { 13 | if (data.metadata.playlistName) { 14 | let playlistName = data.metadata.playlistName 15 | let cover = data.metadata.cover 16 | let tracks = data.tracks 17 | 18 | m.reply(`*Playlist:* ${playlistName}\n*Cover:* ${cover}\n*Total Tracks:* ${tracks.length}`) 19 | 20 | for (let i = 0; i < tracks.length; i++) { 21 | let track = tracks[i] 22 | 23 | if (track.success) { 24 | let { title, artists, album, cover, releaseDate } = track.metadata 25 | conn.sendMessage(m.chat, { 26 | document: { url: track.link }, 27 | mimetype: 'audio/mpeg', 28 | fileName: `${title}.mp3`, 29 | caption: ` 30 | *Title:* ${title} 31 | *Artists:* ${artists} 32 | *Album:* ${album} 33 | *Release Date:* ${releaseDate} 34 | *Cover:* ${cover} 35 | `, 36 | }, { quoted: m }) 37 | 38 | await conn.delay(1500) 39 | } else { 40 | m.reply(`Error: Failed to download track ${i + 1}`) 41 | } 42 | } 43 | } else { 44 | // Jika URL yang diberikan adalah track tunggal 45 | let { title, artists, album, cover, releaseDate } = data.metadata 46 | conn.sendMessage(m.chat, { 47 | document: { url: data.link }, 48 | mimetype: 'audio/mpeg', 49 | fileName: `${title}.mp3`, 50 | caption: ` 51 | *Title:* ${title} 52 | *Artists:* ${artists} 53 | *Album:* ${album} 54 | *Release Date:* ${releaseDate} 55 | *Cover:* ${cover} 56 | `, 57 | }, { quoted: m }) 58 | } 59 | } else { 60 | throw 'Error: Failed to download. Please check the URL and try again.' 61 | } 62 | } catch (err) { 63 | console.error(err) 64 | throw `Error: ${err.message}` 65 | } 66 | } 67 | 68 | handler.help = ['spotify '] 69 | handler.tags = ['downloader'] 70 | handler.command = /^(spotify(dl)?)$/i 71 | handler.limit = 2 72 | handler.register = true 73 | 74 | export default handler 75 | -------------------------------------------------------------------------------- /plugins/tool-jadwaltv.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import axios from 'axios' 3 | import * as cheerio from 'cheerio' 4 | 5 | let handler = async (m, { text }) => { 6 | if (!text) throw 'Input Query' 7 | let res = await jadwalTV(text) 8 | let txt = res.result.map((v) => `[${v.jam.replace('WIB', ' WIB')}] ${v.acara}`).join`\n` 9 | m.reply(`Jadwal TV ${res.channel}\n\n${txt}`) 10 | } 11 | handler.help = ['jadwaltv'] 12 | handler.tags = ['tools'] 13 | handler.command = /^jadwaltv$/i 14 | 15 | handler.register = true 16 | 17 | export default handler 18 | 19 | async function jadwalTV(name) { 20 | let list = JSON.parse(fs.readFileSync('./src/jadwaltv.json', 'utf-8')) 21 | let data = list.find((v) => (new RegExp(name, 'gi')).test(v.channel)), result = [] 22 | if (!data) throw 'List Channel Yg Tersedia:\n\n' + list.map(v => v.channel).sort().join('\n') 23 | let html = (await axios.get(`https://www.jadwaltv.net/${data.isPay ? 'jadwal-pay-tv/' : ''}${data.value}`)).data 24 | let $ = cheerio.load(html) 25 | $('div > table.table').find('tbody > tr').slice(1).each(function () { 26 | let jam = $(this).find('td').eq(0).text() 27 | let acara = $(this).find('td').eq(1).text() 28 | if (!/Jadwal TV/gi.test(acara) && !/Acara/gi.test(acara)) result.push({ jam, acara }) 29 | }) 30 | return { channel: data.channel.toUpperCase(), result } 31 | } 32 | /* 33 | async function listJadwalTV() { 34 | let html = (await axios.get('https://www.jadwaltv.net/jadwal-pay-tv')).data 35 | let $ = cheerio.load(html), result = [] 36 | $('#channelPayTVDropdown.dropdown > option').get().map((v) => { 37 | let name = $(v).text().toLowerCase() 38 | result.push({ value: $(v).val(), channel: name, isPay: true }) 39 | }) 40 | return [ 41 | { value: 'channel/antv', channel: 'antv', isPay: false }, 42 | { value: 'channel/gtv', channel: 'gtv', isPay: false }, 43 | { value: 'channel/indosiar', channel: 'indosiar', isPay: false }, 44 | { value: 'channel/inewstv', channel: 'inews tv', isPay: false }, 45 | { value: 'channel/kompastv', channel: 'kompas tv', isPay: false }, 46 | { value: 'channel/metrotv', channel: 'metro tv', isPay: false }, 47 | { value: 'channel/mnctv', channel: 'mnctv', isPay: false }, 48 | { value: 'channel/nettv', channel: 'net tv', isPay: false }, 49 | { value: 'channel/ochannel', channel: 'ochannel', isPay: false }, 50 | { value: 'channel/rcti', channel: 'rcti', isPay: false }, 51 | { value: 'channel/rtv', channel: 'rtv', isPay: false }, 52 | { value: 'channel/sctv', channel: 'sctv', isPay: false }, 53 | { value: 'channel/trans7', channel: 'trans7', isPay: false }, 54 | { value: 'channel/transtv', channel: 'transtv', isPay: false }, 55 | { value: 'channel/tvone', channel: 'tvone', isPay: false }, 56 | { value: 'channel/tvri', channel: 'tvri', isPay: false }, 57 | ...result 58 | ] 59 | } 60 | */ 61 | -------------------------------------------------------------------------------- /plugins/youtube-ytv.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import fs from 'fs' 3 | import path from 'path' 4 | 5 | let handler = async (m, { conn, command, text, usedPrefix }) => { 6 | if (!text) throw `Usage: ${usedPrefix}${command} ` 7 | 8 | await m.react('🕓') 9 | 10 | const args = text.split(' ') 11 | const videoUrl = args[0] 12 | const resolution = args[1] || '480p' 13 | 14 | const apiUrl = `${APIs.ryzumi}/api/downloader/ytmp4?url=${encodeURIComponent(videoUrl)}&quality=${resolution}` 15 | 16 | try { 17 | const response = await axios.get(apiUrl) 18 | const data = response.data 19 | 20 | if (!data.url) throw 'Download URL not found in API response.' 21 | 22 | const tmpDir = path.join(process.cwd(), 'tmp') 23 | if (!fs.existsSync(tmpDir)) { 24 | fs.mkdirSync(tmpDir, { recursive: true }) 25 | } 26 | 27 | const safeTitle = data.title.replace(/[\\/:*?"<>|]/g, '').slice(0, 50) // amanin nama file 28 | const filePath = path.join(tmpDir, `${safeTitle}.mp4`) 29 | 30 | const writer = fs.createWriteStream(filePath) 31 | const downloadResponse = await axios({ 32 | url: data.url, 33 | method: 'GET', 34 | responseType: 'stream', 35 | }) 36 | 37 | downloadResponse.data.pipe(writer) 38 | 39 | await new Promise((resolve, reject) => { 40 | writer.on('finish', resolve) 41 | writer.on('error', reject) 42 | }) 43 | 44 | const caption = `Ini kak videonya @${m.sender.split('@')[0]} 45 | 46 | *Title*: ${data.title} 47 | *Author*: ${data.author} (${data.authorUrl}) 48 | *Duration*: ${data.lengthSeconds} 49 | *Views*: ${data.views} 50 | *Uploaded*: ${data.uploadDate} 51 | *URL*: ${data.videoUrl} 52 | 53 | *Description*: ${data.description}` 54 | 55 | await conn.sendMessage(m.chat, { 56 | video: { url: filePath }, 57 | mimetype: 'video/mp4', 58 | fileName: `${safeTitle}.mp4`, 59 | caption, 60 | mentions: [m.sender], 61 | contextInfo: { 62 | externalAdReply: { 63 | //showAdAttribution: true, 64 | mediaType: 2, 65 | mediaUrl: data.videoUrl, 66 | title: data.title, 67 | body: 'Video Download', 68 | sourceUrl: data.videoUrl, 69 | thumbnail: await (await conn.getFile(data.thumbnail)).data, 70 | }, 71 | }, 72 | }, { quoted: m }) 73 | 74 | fs.unlink(filePath, () => { }) 75 | 76 | } catch (error) { 77 | console.error(`Error: ${error.message}`) 78 | throw `Gagal: ${error.message || error}` 79 | } 80 | } 81 | 82 | handler.help = ['ytmp4'].map((v) => v + ' ') 83 | handler.tags = ['downloader'] 84 | handler.command = /^(ytmp4)$/i 85 | 86 | handler.limit = 10 87 | handler.register = true 88 | handler.disable = false 89 | 90 | export default handler 91 | -------------------------------------------------------------------------------- /lib/converter.js: -------------------------------------------------------------------------------- 1 | import { promises } from 'fs'; 2 | import { join } from 'path'; 3 | import { spawn } from 'child_process'; 4 | import { fileURLToPath } from 'url'; 5 | 6 | const __dirname = fileURLToPath(new URL('.', import.meta.url)); 7 | 8 | function ffmpeg(buffer, args = [], ext = '', ext2 = '') { 9 | return new Promise(async (resolve, reject) => { 10 | try { 11 | let tmp = join(__dirname, '../tmp', +new Date() + '.' + ext); 12 | let out = tmp + '.' + ext2; 13 | await promises.writeFile(tmp, buffer); 14 | const ffmpegProcess = spawn('ffmpeg', [ 15 | '-y', 16 | '-i', tmp, 17 | ...args, 18 | out 19 | ]); 20 | ffmpegProcess.on('error', (err) => { 21 | console.error('Error spawning ffmpeg:', err); 22 | reject(err); 23 | }); 24 | ffmpegProcess.on('close', async (code) => { 25 | try { 26 | await promises.unlink(tmp); 27 | if (code !== 0) return reject(code); 28 | if (!await promises.access(out).then(() => true).catch(() => false)) { 29 | return reject(new Error('Output file not found')); 30 | } 31 | resolve({ 32 | data: await promises.readFile(out), 33 | filename: out, 34 | delete() { 35 | return promises.unlink(out); 36 | } 37 | }); 38 | } catch (e) { 39 | reject(e); 40 | } 41 | }); 42 | } catch (e) { 43 | reject(e); 44 | } 45 | }); 46 | } 47 | 48 | /** 49 | * Convert Audio to Playable WhatsApp Audio 50 | * @param {Buffer} buffer Audio Buffer 51 | * @param {String} ext File Extension 52 | * @returns {Promise<{data: Buffer, filename: String, delete: Function}>} 53 | */ 54 | function toPTT(buffer, ext) { 55 | return ffmpeg(buffer, [ 56 | '-vn', 57 | '-c:a', 'libopus', 58 | '-b:a', '128k', 59 | '-vbr', 'on', 60 | ], ext, 'ogg'); 61 | } 62 | 63 | /** 64 | * Convert Audio to Playable WhatsApp PTT 65 | * @param {Buffer} buffer Audio Buffer 66 | * @param {String} ext File Extension 67 | * @returns {Promise<{data: Buffer, filename: String, delete: Function}>} 68 | */ 69 | function toAudio(buffer, ext) { 70 | return ffmpeg(buffer, [ 71 | '-vn', 72 | '-c:a', 'libopus', 73 | '-b:a', '128k', 74 | '-vbr', 'on', 75 | '-compression_level', '10' 76 | ], ext, 'opus'); 77 | } 78 | 79 | /** 80 | * Convert Audio to Playable WhatsApp Video 81 | * @param {Buffer} buffer Video Buffer 82 | * @param {String} ext File Extension 83 | * @returns {Promise<{data: Buffer, filename: String, delete: Function}>} 84 | */ 85 | function toVideo(buffer, ext) { 86 | return ffmpeg(buffer, [ 87 | '-c:v', 'libx264', 88 | '-c:a', 'aac', 89 | '-ab', '128k', 90 | '-ar', '44100', 91 | '-crf', '32', 92 | '-preset', 'slow' 93 | ], ext, 'mp4'); 94 | } 95 | 96 | export { 97 | toAudio, 98 | toPTT, 99 | toVideo, 100 | ffmpeg 101 | }; 102 | -------------------------------------------------------------------------------- /plugins/memfess.js: -------------------------------------------------------------------------------- 1 | import { uploadPomf } from '../lib/uploadImage.js' 2 | 3 | let handler = async (m, { conn, text, usedPrefix, command }) => { 4 | conn.menfess = conn.menfess || {} 5 | 6 | if (!text) throw `*Cara penggunaan :*\n\n${usedPrefix + command} nomor|nama pengirim|pesan\n\n*Note:* nama pengirim boleh samaran/anonymous.\n\n*Contoh:* ${usedPrefix + command} ${m.sender.split('@')[0]}|Anonymous|Hai.` 7 | let [jid, name, pesan] = text.split('|') 8 | if (!jid || !name || !pesan) throw `*Cara penggunaan :*\n\n${usedPrefix + command} nomor|nama pengirim|pesan\n\n*Contoh:* ${usedPrefix + command} ${m.sender.split('@')[0]}|Anonymous|Hai.` 9 | 10 | jid = jid.replace(/[^0-9]/g, '') + '@s.whatsapp.net' 11 | let data = (await conn.onWhatsApp(jid))[0] || {} 12 | if (!data.exists) throw 'Nomer tidak terdaftar di whatsapp.' 13 | if (jid === m.sender) throw 'tidak bisa mengirim pesan menfess ke diri sendiri.' 14 | 15 | let mf = Object.values(conn.menfess).find(v => v.status === true) 16 | if (mf) return !0 17 | 18 | let id = Date.now() 19 | let teks = `Hai, kamu menerima pesan Menfess nih.\n\nDari: *${name}*\nPesan:\n${pesan}\n\nMau balas pesan ini kak? Tinggal ketik pesan kakak lalu kirim, nanti saya sampaikan ke *${name}*.`.trim() 20 | 21 | // cek media (reply / lampiran) 22 | let q = m.quoted ? m.quoted : m 23 | let mediaUrl = null 24 | if (q && typeof q.download === 'function') { 25 | try { 26 | let buf = await q.download() 27 | if (buf && Buffer.isBuffer(buf)) { 28 | mediaUrl = await uploadPomf(buf) 29 | } 30 | } catch {} 31 | } 32 | 33 | if (mediaUrl) { 34 | await conn.sendMessage(jid, { 35 | image: { url: mediaUrl }, 36 | caption: teks, 37 | contextInfo: { 38 | externalAdReply: { 39 | title: 'M E N F E S S', 40 | mediaType: 1, 41 | previewType: 0, 42 | renderLargerThumbnail: true, 43 | thumbnailUrl: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRIyz1dMPkZuNleUyfXPMsltHwKKdVddTf4-A&usqp=CAU', 44 | sourceUrl: '' 45 | } 46 | } 47 | }) 48 | } else { 49 | await conn.sendMessage(jid, { 50 | text: teks, 51 | contextInfo: { 52 | externalAdReply: { 53 | title: 'M E N F E S S', 54 | mediaType: 1, 55 | previewType: 0, 56 | renderLargerThumbnail: true, 57 | thumbnailUrl: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRIyz1dMPkZuNleUyfXPMsltHwKKdVddTf4-A&usqp=CAU', 58 | sourceUrl: '' 59 | } 60 | } 61 | }) 62 | } 63 | 64 | m.reply('Berhasil mengirim pesan menfess.') 65 | conn.menfess[id] = { 66 | id, 67 | dari: m.sender, 68 | nama: name, 69 | penerima: jid, 70 | pesan, 71 | status: false 72 | } 73 | return !0 74 | } 75 | 76 | handler.tags = ['memfess'] 77 | handler.help = ['mfs'] 78 | handler.command = /^(mfs|memfess|memfes|confes)$/i 79 | 80 | handler.register = true 81 | handler.private = true 82 | handler.limit = 2 83 | 84 | export default handler 85 | -------------------------------------------------------------------------------- /plugins/internet-cuaca.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | 3 | let handler = async (m, { 4 | text, 5 | usedPrefix, 6 | command 7 | }) => { 8 | if (!text) { 9 | throw `Penggunaan:\n${usedPrefix + command} \n\nContoh:\n${usedPrefix + command} Jakarta`; 10 | } 11 | 12 | await m.react('🕓') 13 | 14 | let teksenc = encodeURIComponent(text); 15 | 16 | let res = await fetch(API('https://api.openweathermap.org', '/data/2.5/weather', { 17 | q: text, 18 | units: 'metric', 19 | appid: '060a6bcfa19809c2cd4d97a212b19273' 20 | })); 21 | 22 | if (!res.ok) { 23 | throw 'Lokasi tidak ditemukan'; 24 | } 25 | 26 | let json = await res.json(); 27 | 28 | if (json.cod != 200) { 29 | throw json; 30 | } 31 | 32 | let gustKmph = json.wind.gust * 3.6; 33 | 34 | let sunriseTime = json.sys.sunrise ? new Date(json.sys.sunrise * 1000).toLocaleTimeString('id-ID', { 35 | hour: '2-digit', 36 | minute: '2-digit', 37 | hour12: false, 38 | timeZone: 'Asia/Jakarta' 39 | }) : 'Tidak Tersedia'; 40 | let sunsetTime = json.sys.sunset ? new Date(json.sys.sunset * 1000).toLocaleTimeString('id-ID', { 41 | hour: '2-digit', 42 | minute: '2-digit', 43 | hour12: false, 44 | timeZone: 'Asia/Jakarta' 45 | }) : 'Tidak Tersedia'; 46 | let predictionTime = new Date(json.dt * 1000 + json.timezone * 1000).toLocaleString('id-ID', { 47 | timeZone: 'Asia/Jakarta' 48 | }); 49 | 50 | let groundLevelPressure = json.main.grnd_level !== undefined ? json.main.grnd_level + ' hPa' : 'Tidak Tersedia'; 51 | let seaLevelPressure = json.main.sea_level !== undefined ? json.main.sea_level + ' hPa' : 'Tidak Tersedia'; 52 | 53 | m.reply(` 54 | 🤩 Koordinat: ${json.coord.lat}, ${json.coord.lon} https://www.google.com/maps/place/${teksenc}/@${json.coord.lat},${json.coord.lon} 55 | 🌍 Lokasi: ${json.name}, ${json.sys.country} 56 | 🌦️ Cuaca: ${json.weather[0].description}, intinya: ${json.weather[0].main} 57 | 🌡️ Suhu saat ini: ${json.main.temp} °C 58 | 🔥 Suhu tertinggi: ${json.main.temp_max} °C 59 | ❄️ Suhu terendah: ${json.main.temp_min} °C 60 | 😊 Terasa seperti: ${json.main.feels_like} °C 61 | 💧 Kelembapan: ${json.main.humidity} % 62 | 💨 Angin: ${json.wind.speed} km/jam, ${json.wind.deg} derajat, guncangan ${gustKmph.toFixed(2)} km/jam 63 | ☔ Curah Hujan (1 Jam): ${json.rain ? json.rain['1h'] || 0 : 0} mm 64 | ☁ Persen Awan: ${json.clouds ? json.clouds.all || 0 : 0} % 65 | 🌬️ Tekanan (Udara): ${json.main.pressure} hPa 66 | ⛳ Tingkat Tanah: ${groundLevelPressure} 67 | 🌊 Tingkat Laut: ${seaLevelPressure} 68 | 👀 Jarak Pandang: ${json.visibility ? `${(json.visibility / 1000).toFixed(2)} km` : 'Tidak Tersedia'} 69 | 🔮 Prediksi di waktu: ${predictionTime} WIB 70 | 🌄 Waktu Sunrise: ${sunriseTime} WIB 71 | 🌅 Waktu Sunset: ${sunsetTime} WIB 72 | `.trim()); 73 | }; 74 | 75 | handler.help = ['cuaca'] 76 | handler.tags = ['internet'] 77 | handler.command = /^(cuaca|weather)$/i 78 | 79 | handler.register = true 80 | 81 | export default handler --------------------------------------------------------------------------------