├── .gitignore ├── Dockerfile ├── app.js ├── config.js ├── docker-compose.yml ├── nodemon.json ├── package.json ├── readme.md ├── schema.js ├── src ├── app │ ├── bootstrap.js │ ├── event │ │ ├── index.js │ │ ├── interval.js │ │ ├── onGroupParticipantUpdate.js │ │ └── onMessageUpsert.js │ └── socket.js ├── command │ ├── ai │ │ ├── custom.js │ │ ├── llama3.js │ │ ├── lumin.js │ │ └── openai.js │ ├── anime │ │ ├── anime-info.js │ │ ├── fanart.js │ │ ├── neko.js │ │ ├── nsfw-waifu.js │ │ └── waifu.js │ ├── blockchain │ │ ├── claim.js │ │ ├── getbalance.js │ │ ├── holders.js │ │ ├── mine.js │ │ ├── progress-mining.js │ │ ├── stats.js │ │ └── transfer.js │ ├── downloader │ │ ├── facebook.js │ │ ├── git.js │ │ ├── instagram.js │ │ ├── tiktok.js │ │ ├── yt.js │ │ └── ytmp3.js │ ├── fun │ │ └── tebak-angka.js │ ├── games │ │ ├── blackjack.js │ │ └── tictactoe.js │ ├── group │ │ ├── add.js │ │ ├── antilink.js │ │ ├── del.js │ │ ├── group-info.js │ │ ├── hidetag.js │ │ ├── kick.js │ │ ├── leaderboard.js │ │ ├── link.js │ │ ├── mode.js │ │ ├── random-kick.js │ │ ├── record-activity.js │ │ ├── timeout-list.js │ │ ├── timeout.js │ │ ├── welcome-message.js │ │ └── welcome.js │ ├── info │ │ ├── change-name.js │ │ ├── creator.js │ │ ├── ping.js │ │ └── profile.js │ ├── internet │ │ ├── gempa.js │ │ ├── lyric.js │ │ └── ssweb.js │ ├── menu-owner.js │ ├── menu.js │ ├── owner │ │ ├── add-balance.js │ │ ├── block.js │ │ ├── bot-info.js │ │ ├── clear.js │ │ ├── exc.js │ │ ├── exif.js │ │ ├── get-group.js │ │ ├── icon.js │ │ ├── join.js │ │ ├── lang.js │ │ ├── leave.js │ │ ├── mode.js │ │ ├── owners.js │ │ ├── prefix.js │ │ ├── set-balance.js │ │ ├── setpp.js │ │ ├── unblock.js │ │ └── unreg.js │ ├── store │ │ └── limit.js │ ├── test.js │ └── tools │ │ ├── attp.js │ │ ├── nobg.js │ │ ├── readmore.js │ │ ├── sticker.js │ │ ├── take.js │ │ ├── toimg.js │ │ └── tovid.js ├── middleware │ ├── activity-record.js │ ├── antilink.js │ ├── antinfsw-media.js │ ├── app.js │ ├── blackjack.js │ ├── bot-mode.js │ ├── group-mode.js │ ├── limit.js │ ├── nakiri.js │ ├── register.js │ ├── tictactoe.js │ ├── timeout-expired.js │ └── timeout.js └── utils │ ├── attp.js │ ├── blockchain │ ├── block.js │ └── index.js │ ├── currency.js │ ├── db.js │ ├── exp.js │ ├── games │ ├── blackjack.js │ └── tictactoe.js │ ├── loadCommands.js │ ├── log.js │ ├── moment.js │ ├── ruhend-scrapper │ ├── facebook.js │ └── tiktok.js │ ├── scraper.js │ ├── serialize.js │ ├── stickerMaker.js │ ├── timer2.js │ ├── uploader.js │ └── validate-url.js ├── storage ├── bug.pdf ├── databases │ └── .gitignore ├── media │ ├── coin.jpg │ └── test.png ├── session │ └── .gitignore └── temp │ └── .gitignore └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | 4 | RUN apk add --no-cache \ 5 | g++ \ 6 | cairo-dev \ 7 | libjpeg-turbo-dev \ 8 | pango-dev \ 9 | giflib-dev \ 10 | pixman-dev \ 11 | make \ 12 | python3 \ 13 | py3-pip \ 14 | pkgconfig 15 | 16 | WORKDIR /app 17 | 18 | COPY package*.json ./ 19 | RUN npm install 20 | COPY . . 21 | CMD ["npm", "run", "start"] 22 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | // try { 2 | // require('./config.js') 3 | // } catch { 4 | // log.error('config.js not found!') 5 | // process.exit(1) 6 | // } 7 | 8 | require('./src/app/bootstrap.js') 9 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | SESSION_NAME : "cihuy", 3 | STORAGE_PATH : __dirname + "/storage", 4 | STORAGE_SESSION : __dirname + "/storage/session", 5 | STORAGE_DB : __dirname + "/storage/databases", 6 | 7 | ...require("./schema.js") 8 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | app: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | 9 | command: npm run start 10 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "js", 4 | "ignore": [], 5 | "delay": "3" 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "self-bot", 3 | "version": "1.0.0", 4 | "main": "app.js", 5 | "scripts": { 6 | "start": "node app.js", 7 | "dev": "nodemon app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "description": "", 14 | "dependencies": { 15 | "@ptkdev/logger": "^1.8.0", 16 | "@whiskeysockets/baileys": "^6.7.7", 17 | "axios": "^1.7.5", 18 | "canvas": "^2.11.2", 19 | "cheerio": "^1.0.0", 20 | "crypto": "^1.0.1", 21 | "dotenv": "^16.4.5", 22 | "fluent-ffmpeg": "^2.1.3", 23 | "form-data": "^4.0.1", 24 | "formdata-node": "^6.0.3", 25 | "fs": "^0.0.1-security", 26 | "got": "^11.7.0", 27 | "jimp": "^0.16.13", 28 | "libphonenumber-js": "^1.11.7", 29 | "link-preview-js": "^3.0.5", 30 | "lmdb": "^3.1.3", 31 | "moment-timezone": "^0.5.45", 32 | "node-webpmux": "^3.2.0", 33 | "nodemon": "^3.1.7", 34 | "pino": "^9.3.2", 35 | "qrcode-terminal": "^0.12.0", 36 | "readline": "^1.3.0", 37 | "tar": "^7.4.3", 38 | "ultimate-text-to-image": "^1.0.1", 39 | "zod": "^3.23.8" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Whangsaf Bot Open Source le 2 | Bot ini opensource silahkan di pakai. beberapa command seperti `virtex`, `bug whatsapp` saya jadikan kusus premium aja biar gak di salah gunakan, jika ingin bisa contact saya. 3 | 4 | ### Require 5 | - Node 20.x 6 | - ffmpeg 7 | 8 | ### Install 9 | ```bash 10 | git clone https://github.com/ilsyaa/lazy-whatsapp-bot 11 | ``` 12 | ```bash 13 | cd lazy-whatsapp-bot 14 | ``` 15 | ```bash 16 | npm install 17 | ``` 18 | ### Run BOT 19 | ```bash 20 | npm run start 21 | ``` 22 | 23 | ### Development 24 | ```bash 25 | npm run dev 26 | ``` 27 | 28 | 29 | 30 | 31 | 32 | Star History Chart 33 | 34 | 35 | -------------------------------------------------------------------------------- /schema.js: -------------------------------------------------------------------------------- 1 | const moment = require('./src/utils/moment.js') 2 | 3 | module.exports = { 4 | /* 5 | #Database Schema 6 | Default Schema and value database. 7 | 8 | Important For Bot Schema: 9 | - You can change the bot settings via commands, 10 | or you can make changes manually via the configuration with the condition that after making changes you need to run the /reset-db-bot command. 11 | */ 12 | DATABASE_SCHEMA: { 13 | bot : { 14 | mode: 'public', 15 | lang: 'id', 16 | prefix: ['/', '.', '!'], 17 | owners: { 18 | '6285174902345': 'Ilsya', 19 | // '628xxx': 'Name', 20 | }, 21 | exif: { 22 | pack: "BOT 6285731618404", 23 | author: "Owner Ilsya", 24 | }, 25 | created_at: moment(), 26 | updated_at: moment(), 27 | }, 28 | user : { 29 | plan: "free", // free or pro 30 | plan_expire: false, // false = unlimited 31 | limit: 20, // false -> unlimited 32 | exp: 0, 33 | balance: 1000000, // poin 34 | blacklist: false, // false = not in blacklist, true = in blacklist permanently, timestamp = in blacklist for some time 35 | blacklist_reason: '', // reason for blacklist 36 | daily: null, 37 | updated_at: moment(), // update every time using bot 38 | created_at: moment(), // create time 39 | }, 40 | group : { 41 | mode: 'admin-only', // admin-only or all 42 | antilink: false, 43 | nsfw: false, 44 | welcome: false, 45 | welcome_message: null, 46 | timeouts: {}, 47 | activity_record: false, 48 | member_activity: {}, 49 | updated_at: moment(), 50 | created_at: moment(), 51 | }, 52 | blockchain: { 53 | difficulty: 2, 54 | miningReward: 1000000, // 1jt 55 | maxSupply: 100000000000,// 1 miliar 56 | currentSupply: 0, 57 | blocksMined: 0, 58 | blockRewardHalvingInterval: 1000, 59 | totalTransactions: 0 60 | } 61 | }, 62 | } -------------------------------------------------------------------------------- /src/app/bootstrap.js: -------------------------------------------------------------------------------- 1 | const db = require('../utils/db.js') 2 | const log = require('../utils/log.js') 3 | const middleware = require('../middleware/app.js') 4 | const start = async() => { 5 | log.info("Starting bot...") 6 | await db.init() 7 | log.info(`Loaded ${middleware.size} middleware.`) 8 | require("../utils/loadCommands.js").loadCommands() 9 | require("./socket.js") 10 | } 11 | 12 | start() -------------------------------------------------------------------------------- /src/app/event/index.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = async (sock) => { 5 | sock.public = false 6 | require('./interval.js')(sock) 7 | require('./onMessageUpsert.js')(sock) 8 | require('./onGroupParticipantUpdate.js')(sock) 9 | 10 | sock.ev.on("call", async (callsList) => { 11 | for (const call of callsList) { 12 | await sock.rejectCall(call.id, call.from); 13 | } 14 | }); 15 | 16 | const updateName = async (update) => { 17 | // { id: 'abc@s.whatsapp.net', name: 'name' }, 18 | } 19 | 20 | sock.ev.on('contacts.upsert', updateName) 21 | sock.ev.on('contacts.set', updateName) 22 | 23 | sock.ev.on('groups.update', async (update) => { 24 | for (const group of update) { 25 | await db.update(db.group, group.id, { 26 | name: group.subject, 27 | updated_at: moment() 28 | }) 29 | } 30 | }); 31 | 32 | sock.ev.on('messages.reaction', async (reactions) => { 33 | // console.log(reactions); 34 | }); 35 | } -------------------------------------------------------------------------------- /src/app/event/interval.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | const currency = require('../../utils/currency.js') 4 | const { BlockchainDB } = require('../../utils/blockchain/index.js') 5 | const { delay } = require('@whiskeysockets/baileys') 6 | const config = require('../../../config.js') 7 | const fs = require('fs') 8 | const path = require('path') 9 | 10 | module.exports = async (sock) => { 11 | setInterval(async () => { 12 | if(!sock?.connected) return 13 | sendBlockchain() 14 | }, 30000); // 1 minute 15 | 16 | async function sendBlockchain() { 17 | const minepending = await db.blockchain.mine.getRange(); 18 | for (const mine of minepending) { 19 | if (moment().valueOf() > mine.value.remaining) { 20 | const result = await new BlockchainDB().mine(mine.value.address); 21 | db.blockchain.mine.remove(mine.value.address); 22 | let text = `*\`❖ Mining Blockchain Success\`*\n\n`; 23 | text += `▷ *Address*: ${mine.value.address.split('@')[0]}\n` 24 | text += `▷ *Reward*: ${currency.format(result.reward)}\n` 25 | text += `▷ *Remaining Supply*: ${currency.format(result.remainingSupply)}\n` 26 | text += `▷ *Blocks Until Halving*: ${currency.format(result.blocksUntilHalving)}\n\n` 27 | text += `▷ *Limit used*: ${mine.value.limit}\n` 28 | text += `▷ *Current Time*: ${moment().format('DD-MM-YYYY HH:mm:ss')}` 29 | _sendMessage(mine.value.m.chat, { 30 | text: text, 31 | contextInfo: { 32 | mentionedJid: [ mine.value.address ], 33 | externalAdReply: { 34 | title: `❖ Mining Success`, 35 | body: `▷ Blockchain`, 36 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 37 | sourceUrl: 'https://ilsya.my.id', 38 | mediaType: 1, 39 | // renderLargerThumbnail: true 40 | } 41 | } 42 | }, { quoted: mine.value.m }) 43 | } 44 | } 45 | } 46 | 47 | async function _sendMessage (jid, content, options) { 48 | await sock.presenceSubscribe(jid) 49 | await delay(500) 50 | await sock.sendPresenceUpdate('composing', jid) 51 | await delay(500) 52 | await sock.sendPresenceUpdate('paused', jid) 53 | 54 | options = { ...options, ...{ ephemeralExpiration: true } }; 55 | return await sock.sendMessage(jid, content, options) 56 | } 57 | } -------------------------------------------------------------------------------- /src/app/event/onGroupParticipantUpdate.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js'); 2 | 3 | module.exports = groupParticipant = async (sock) => { 4 | sock.ev.on('group-participants.update', async (update) => { 5 | switch (update.action) { 6 | case 'add': 7 | await _welcome(sock, update) 8 | break 9 | case 'remove': 10 | break 11 | } 12 | }) 13 | } 14 | 15 | const _welcome = async (sock, update) => { 16 | const dbgroup = await db.group.get(update.id) 17 | const featchGroup = await sock.groupMetadata(update.id) || (sock.chats[id] || {}).metadata 18 | if(!dbgroup) return 19 | if(!dbgroup.welcome) return 20 | for (const participant of update.participants) { 21 | let avatar = "https://i.ibb.co.com/1QRWZTd/146de169d3133554a6d907b837d31377.jpg"; 22 | const mention = '@'+participant.replace('@s.whatsapp.net', ''); 23 | let caption = `Selamat datang @${participant.replace('@s.whatsapp.net', '')} 👋` 24 | try{ 25 | avatar = await sock.profilePictureUrl(participant, 'image'); 26 | } catch { 27 | } finally { 28 | try { 29 | sock.sendMessage(update.id, { 30 | text: dbgroup?.welcome_message ? dbgroup.welcome_message.replace(/{group\.name}/g, dbgroup.name).replace(/{mention}/g, mention) : caption, 31 | contextInfo: { 32 | mentionedJid: [ participant ], 33 | externalAdReply: { 34 | title: `❖ ${dbgroup.name}`, 35 | body: `▷ ${featchGroup.size} member`, 36 | thumbnailUrl: avatar, 37 | sourceUrl: 'https://ilsya.my.id', 38 | mediaType: 1, 39 | // renderLargerThumbnail: true 40 | } 41 | } 42 | }, { ephemeralExpiration: true }) 43 | } catch (error) { 44 | console.error(error); 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/app/event/onMessageUpsert.js: -------------------------------------------------------------------------------- 1 | const { serialize, updateAdminStatus } = require('../../utils/serialize.js'); 2 | const { commands } = require('../../utils/loadCommands.js') 3 | const config = require('../../../config.js'); 4 | const db = require('../../utils/db.js') 5 | const moment = require('../../utils/moment.js') 6 | const middleware = require('../../middleware/app.js') 7 | 8 | module.exports = upsert = async (sock) => { 9 | sock.ev.on('messages.upsert', async (update) => { 10 | try { 11 | const { messages, type } = update 12 | let m = messages[0] 13 | if (m.message?.ephemeralMessage) m.message = m.message.ephemeralMessage.message; 14 | if (m.message?.viewOnceMessageV2) m.message = m.message.viewOnceMessageV2.message; 15 | if (m.message?.viewOnceMessageV2Extension) m.message = m.message.viewOnceMessageV2Extension.message; 16 | if (m.message?.documentWithCaptionMessage) m.message = m.message.documentWithCaptionMessage.message; 17 | if (!m.message) return 18 | if (m.key && m.key.remoteJid == "status@broadcast") return 19 | if (!m.key.fromMe && !type === 'notify') return 20 | if (m.key.id.startsWith('BAE5') && m.key.id.length === 16) return 21 | m = serialize(sock, m) 22 | await sock.readMessages([m.key]) 23 | await updateAdminStatus(sock, m); 24 | m.db.group = await _dbGroupHandler(sock, m) 25 | m.db.user = await db.user.get(m.sender) || null; 26 | m.lang = (msg) => _lang(msg, m); 27 | const command = Array.from(commands.values()).find((v) => v.cmd.find((x) => x.toLowerCase() == m.body.commandWithoutPrefix.toLowerCase())); 28 | const $next = await _middleware(sock, m, middleware, command) 29 | if(!command) return 30 | if(typeof $next == 'object' && !$next.continueCommand) return 31 | if(!command?.withoutPrefix && !m.body.prefix) return 32 | _userOnlineHandler(sock, m) 33 | m.commandLimit = (command.limit || 0) 34 | await command.run({m , sock}) 35 | // console.log(m.db); 36 | } catch (error) { 37 | console.error(error); 38 | } 39 | }) 40 | } 41 | 42 | const _middleware = async (sock, m, middlewares, command) => { 43 | let $next = true 44 | for (let [key, middleware] of middlewares.entries()) { 45 | try { 46 | if(!command?.withoutMiddleware) { 47 | await middleware.handler(sock, m, true, command) 48 | } else if (!command?.withoutMiddleware.includes(key)) { 49 | await middleware.handler(sock, m, true, command) 50 | } 51 | } catch (error) { 52 | if(!error?.hideLogs) console.log(error); 53 | $next = error 54 | if(error?.break) break 55 | } 56 | } 57 | return $next 58 | } 59 | 60 | const _userOnlineHandler = async (sock, m) => { 61 | if(!m.db?.user) return 62 | db.update(db.user, m.sender, { 63 | updated_at: moment(), 64 | }) 65 | } 66 | 67 | const _dbGroupHandler = async (sock, m) => { 68 | let dbGroupData = null; 69 | if(m.isGroup) { 70 | const group = m.isGroup.groupMetadata 71 | dbGroupData = await db.group.get(group.id) 72 | if(!dbGroupData) { 73 | await db.group.put(group.id, { 74 | ...{ name: group.subject }, 75 | ...config.DATABASE_SCHEMA.group 76 | }) 77 | dbGroupData = await db.group.get(group.id) 78 | } 79 | } 80 | return dbGroupData 81 | } 82 | 83 | const _lang = (msg, m) => { 84 | let lang = 'id', res = msg 85 | 86 | if(m.isGroup && m.db.group?.lang) { 87 | lang = m.db.group.lang 88 | } else if(m.db.bot.lang) { 89 | lang = m.db.bot.lang 90 | } 91 | 92 | // copy object 93 | res = { ...res[lang] } 94 | for (const [key, value] of Object.entries(res)) { 95 | if (typeof value === 'object') { 96 | for (let i = 0; i < value.length; i++) { 97 | res[key][i] = value[i].replaceAll('{prefix}', m.body.prefix) 98 | } 99 | } else { 100 | res[key] = value.replaceAll('{prefix}', m.body.prefix) 101 | } 102 | } 103 | return res 104 | } -------------------------------------------------------------------------------- /src/app/socket.js: -------------------------------------------------------------------------------- 1 | const config = require("../../config.js"); 2 | const log = require("../utils/log.js") 3 | const { default: makeWASocket, 4 | DisconnectReason, 5 | useMultiFileAuthState, 6 | makeCacheableSignalKeyStore, 7 | PHONENUMBER_MCC 8 | } = require("@whiskeysockets/baileys") 9 | const NodeCache = require("node-cache") 10 | const pino = require("pino") 11 | const path = require("path"); 12 | 13 | const startSocket = async () => { 14 | let retryCount = 0; 15 | const msgRetryCounterCache = new NodeCache() 16 | const { state, saveCreds } = await useMultiFileAuthState(path.join(config.STORAGE_SESSION, config.SESSION_NAME)); 17 | const sock = makeWASocket({ 18 | printQRInTerminal: true, 19 | auth: { 20 | creds: state.creds, 21 | keys: makeCacheableSignalKeyStore(state.keys, pino().child({ 22 | level: 'silent', 23 | stream: 'store' 24 | })), 25 | }, 26 | logger: pino({ level: "silent" }), 27 | browser: ['VelixS', 'Safari', '3.0'], 28 | markOnlineOnConnect: true, 29 | generateHighQualityLinkPreview: true, 30 | patchMessageBeforeSending: (message) => { 31 | const requiresPatch = !!( 32 | message.buttonsMessage 33 | || message.templateMessage 34 | || message.listMessage 35 | ); 36 | if (requiresPatch) { 37 | message = { 38 | viewOnceMessage: { 39 | message: { 40 | messageContextInfo: { 41 | deviceListMetadataVersion: 2, 42 | deviceListMetadata: {}, 43 | }, 44 | ...message, 45 | }, 46 | }, 47 | }; 48 | } 49 | return message; 50 | }, 51 | msgRetryCounterCache, 52 | defaultQueryTimeoutMs: undefined, 53 | }); 54 | 55 | require('./event')(sock) 56 | 57 | try { 58 | sock.ev.on('connection.update', (update) => { 59 | const { connection, lastDisconnect } = update 60 | if (connection == "connecting") { 61 | log.debug(`SESSION : Conecting.`) 62 | } 63 | if (connection === "close") { 64 | const code = lastDisconnect?.error?.output?.statusCode || lastDisconnect?.error?.output?.payload?.statusCode 65 | sock.connected = false 66 | let retryAttempt = retryCount; 67 | let shouldRetry; 68 | if (code != DisconnectReason.loggedOut && retryAttempt < 20) { 69 | shouldRetry = true; 70 | } 71 | if (shouldRetry) { 72 | retryAttempt++; 73 | } 74 | if (shouldRetry) { 75 | retryCount = retryAttempt 76 | startSocket(); 77 | } else { 78 | log.error(`SESSION : Disconnected.`) 79 | retryCount = 0 80 | sock?.logout() 81 | } 82 | } 83 | if (connection == "open") { 84 | log.info(`SESSION : Connected.`) 85 | sock.connected = true 86 | retryCount = 0 87 | } 88 | }) 89 | sock.ev.on("creds.update", async () => { 90 | await saveCreds(); 91 | }) 92 | } catch (e) { 93 | log.error("SOCKET : " + e) 94 | } 95 | } 96 | 97 | startSocket() -------------------------------------------------------------------------------- /src/command/ai/custom.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "custom-ai", 5 | description : "Test Prompt AI", 6 | cmd : ['ai', 'nakiri'], 7 | menu : { 8 | label : 'ai', 9 | example : "text", 10 | }, 11 | run : async({ m, sock }) => { 12 | m._reply('Kamu bisa langsung ngobrol dengan Nakiri! Di dalam grup, cukup mention nakiri, balas pesan dari Nakiri, atau kirim pertanyaan sambil menyebut namanya. Kalau di personal chat, langsung aja kirim chat nanti langsung di balas.') 13 | } 14 | } -------------------------------------------------------------------------------- /src/command/ai/llama3.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "llama3", 5 | description : "AI Llama3", 6 | cmd : ['llm', 'llama3'], 7 | menu : { 8 | label : 'ai', 9 | example : "text", 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 14 | m._react(m.key, '🔍') 15 | let json = { 16 | model: "meta-llama/Meta-Llama-3.1-405B-Instruct", 17 | messages: [ 18 | { 19 | role: "system", 20 | content: "Be a helpful assistant", 21 | }, 22 | { 23 | role: "user", 24 | content: m.body.arg, 25 | }, 26 | ], 27 | presence_penalty: 0.1, 28 | frequency_penalty: 0.1, 29 | top_k: 100, 30 | }; 31 | const { data } = await axios.post( 32 | "https://imphnen-ai.vercel.app/api/llm/llama", 33 | json, 34 | ); 35 | await m._sendMessage(m.chat, { text: `*• Model :* ${data.data.model}\n` + data.data.choices[0].message.content }, { quoted: m }) 36 | m._react(m.key, '✅') 37 | } catch(error) { 38 | m._react(m.key, '❌') 39 | await m._reply(error.message) 40 | } 41 | } 42 | } 43 | 44 | const msg = { 45 | id: { 46 | ex: 'penggunaan: {prefix}llm `text`' 47 | }, 48 | en: { 49 | ex: 'usage: {prefix}llm `text`' 50 | } 51 | } -------------------------------------------------------------------------------- /src/command/ai/lumin.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "lumin-ai-image", 5 | description : "Identifer Image", 6 | cmd : ['lumin', 'identifer'], 7 | menu : { 8 | label : 'ai', 9 | example : "text", 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 14 | if(!['imageMessage'].includes(m.quoted?.mtype || m.mtype)) return m._reply(m.lang(msg).req); 15 | const { buffer } = m.quoted ? await m.quoted.download() : await m.download() 16 | m._react(m.key, '🔍') 17 | const response = await axios.post('https://luminai.my.id/', { 18 | content: m.body.arg, 19 | imageBuffer: buffer 20 | }); 21 | 22 | await m._sendMessage(m.chat, { text: response.data.result }, { quoted: m }) 23 | m._react(m.key, '✅') 24 | } catch(error) { 25 | m._react(m.key, '❌') 26 | await m._reply(error.message) 27 | } 28 | } 29 | } 30 | 31 | const msg = { 32 | id: { 33 | ex: 'Penggunaan: {prefix}lumin ``\n\n*Keterangan:*\nIdentifer gambar dengan ai\n- **: Prompt yang ingin Anda gunakan.', 34 | req: 'Kirim gambar untuk di identifikasi.' 35 | }, 36 | en: { 37 | ex: 'Usage: {prefix}lumin ``\n\n*Description:*\nIdentifer image with ai\n- **: Prompt parameter you want to use.', 38 | req: 'Send image to be identified.' 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/command/ai/openai.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "gpt", 5 | description : "AI OpenAI", 6 | cmd : ['gpt', 'openai'], 7 | menu : { 8 | label : 'ai', 9 | example : "text", 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 14 | m._react(m.key, '🔍') 15 | const res = await axios.get(`https://widipe.com/openai?text=${m.body.arg}`) 16 | await m._sendMessage(m.chat, { text: res.data.result }, { quoted: m }) 17 | m._react(m.key, '✅') 18 | } catch(error) { 19 | m._react(m.key, '❌') 20 | await m._reply(error.message) 21 | } 22 | } 23 | } 24 | 25 | const msg = { 26 | id: { 27 | ex: 'penggunaan: {prefix}gpt `text`' 28 | }, 29 | en: { 30 | ex: 'usage: {prefix}gpt `text`' 31 | } 32 | } -------------------------------------------------------------------------------- /src/command/anime/anime-info.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "anime-info", 5 | description : "Search Anime by title", 6 | cmd : ['animeinfo'], 7 | menu : { 8 | label : 'anime', 9 | example : "text", 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 14 | m._react(m.key, '🔍') 15 | const res = await axios.get(`https://api.jikan.moe/v4/anime?q=${encodeURIComponent(m.body.arg)}`) 16 | if(res.data.data.length == 0) return m._reply(m.lang(msg).notFound) 17 | let anime = res.data.data[0] 18 | let genreList = anime.genres.map((genre) => genre.name).join(', '); 19 | let caption = `*${anime.title}*\nJapan: ${anime.title_japanese}\nType: ${anime.type}\nGenres: ${genreList}\nScore: ${anime.score}\nStatus: ${anime.status}\n\n_${anime.url}_` 20 | await m._sendMessage(m.chat, { image : { url : res.data.data[0].images.jpg.image_url }, caption }, { quoted: m }) 21 | m._react(m.key, '✅') 22 | } catch(error) { 23 | m._react(m.key, '❌') 24 | await m._reply(error.message) 25 | } 26 | } 27 | } 28 | 29 | const msg = { 30 | id: { 31 | ex: 'penggunaan: {prefix}animeinfo `judul anime`', 32 | notFound: 'Anime Tidak ditemukan' 33 | }, 34 | en: { 35 | ex: 'usage: {prefix}animeinfo `judul anime`', 36 | notFound: 'Anime not found' 37 | } 38 | } -------------------------------------------------------------------------------- /src/command/anime/fanart.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "anime-fanart", 5 | description : "Generate Anime Fanart", 6 | cmd : ['fanart'], 7 | menu : { 8 | label : 'anime', 9 | }, 10 | run : async({ m, sock }) => { 11 | try { 12 | m._react(m.key, '🔍') 13 | const res = await axios.get(`https://api.waifu.pics/sfw/waifu`) 14 | await m._sendMessage(m.chat, { image : { url : res.data.url } }, { quoted: m }) 15 | m._react(m.key, '✅') 16 | } catch(error) { 17 | m._react(m.key, '❌') 18 | await m._reply(error.message) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/command/anime/neko.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "anime-neko", 5 | description : "Random Anime Neko", 6 | cmd : ['neko'], 7 | menu : { 8 | label : 'anime', 9 | }, 10 | run : async({ m, sock }) => { 11 | try { 12 | m._react(m.key, '🔍') 13 | const res = await axios.get(`https://api.waifu.pics/sfw/neko`) 14 | await m._sendMessage(m.chat, { image : { url : res.data.url } }, { quoted: m }) 15 | m._react(m.key, '✅') 16 | } catch(error) { 17 | m._react(m.key, '❌') 18 | await m._reply(error.message) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/command/anime/nsfw-waifu.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios') 2 | 3 | module.exports = { 4 | name : "anime-nsfw-waifu", 5 | description : "Random Anime NSFW Waifu", 6 | cmd : ['nsfw-waifu'], 7 | menu : { 8 | label : 'anime', 9 | }, 10 | run : async({ m, sock }) => { 11 | if(!m.senderIsOwner && m.isGroup && !m.db.group?.nsfw) return m._reply(m.lang(msg).nsfw) 12 | try { 13 | m._react(m.key, '🔍') 14 | const res = await axios.get(`https://api.waifu.pics/nsfw/waifu`) 15 | await m._sendMessage(m.chat, { image : { url : res.data.url } }, { quoted: m }) 16 | m._react(m.key, '✅') 17 | } catch(error) { 18 | m._react(m.key, '❌') 19 | await m._reply(error.message) 20 | } 21 | } 22 | } 23 | 24 | const msg = { 25 | id: { 26 | nfsw: 'NSFW mode tidak diaktifkan di grup ini.' 27 | }, 28 | en: { 29 | nfsw: 'NSFW mode is not enabled in this group.' 30 | } 31 | } -------------------------------------------------------------------------------- /src/command/anime/waifu.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name : "anime-waifu", 5 | description : "Random Waifu", 6 | cmd : ['waifu'], 7 | menu : { 8 | label : 'anime', 9 | }, 10 | run : async({ m, sock }) => { 11 | try { 12 | m._react(m.key, '🔍') 13 | const res = await axios.get(`https://api.waifu.pics/sfw/waifu`) 14 | await m._sendMessage(m.chat, { image : { url : res.data.url } }, { quoted: m }) 15 | m._react(m.key, '✅') 16 | } catch(error) { 17 | m._react(m.key, '❌') 18 | await m._reply(error.message) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/command/blockchain/claim.js: -------------------------------------------------------------------------------- 1 | const { BlockchainDB, Transaction } = require('../../utils/blockchain/index.js'); 2 | const blockchain = new BlockchainDB(); 3 | const currency = require('../../utils/currency.js'); 4 | const moment = require('../../utils/moment.js'); 5 | const config = require('../../../config.js'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const exp = require('../../utils/exp.js'); 9 | const db = require('../../utils/db.js'); 10 | 11 | module.exports = { 12 | name: "blockchain-daily", 13 | description: "Daily Claim", 14 | cmd: ['claim', 'daily'], 15 | menu: { 16 | label: 'blockchain', 17 | }, 18 | run: async ({ m, sock }) => { 19 | if(m.db.user?.daily) { 20 | if(moment(m.db.user.daily).startOf('day').diff(moment().startOf('day'), 'days') < 1) return m._reply(m.lang(msg).dailyClaimed) 21 | } 22 | 23 | let blockchainDaily = 50000; 24 | let expDaily = Math.floor(Math.random() * 500) + 10; 25 | let limitDaily = 15; 26 | 27 | try { 28 | await blockchain.transfer('unknown@s.whatsapp.net', m.sender, blockchainDaily); 29 | } catch(e) { 30 | blockchainDaily = 0 31 | } 32 | exp.add(m.sender, expDaily); 33 | db.update(db.user, m.sender, { daily: moment(), limit: (limitDaily + parseInt(m.db.user.limit)) }); 34 | 35 | let text = `*\`❖ Daily Event\`*\n\n`; 36 | text += `▷ *Blockchain*: ${currency.format(blockchainDaily)}\n` 37 | text += `▷ *Exp*: ${currency.format(expDaily)}\n` 38 | text += `▷ *Limit*: ${currency.format(limitDaily)}\n` 39 | m._sendMessage(m.chat, { 40 | text: text, 41 | contextInfo: { 42 | mentionedJid: [], 43 | externalAdReply: { 44 | title: `❖ Daily Event`, 45 | body: `▷ Nakiri BOT`, 46 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 47 | sourceUrl: 'https://ilsya.my.id', 48 | mediaType: 1, 49 | // renderLargerThumbnail: true 50 | } 51 | } 52 | }, { quoted: m }) 53 | } 54 | } 55 | 56 | const msg = { 57 | id : { 58 | dailyClaimed: 'Kamu sudah mengklaim harian anda 😺', 59 | }, 60 | en : { 61 | dailyClaimed: 'You have already claimed your daily reward today', 62 | } 63 | } -------------------------------------------------------------------------------- /src/command/blockchain/getbalance.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js'); 2 | const moment = require('../../utils/moment.js'); 3 | const { BlockchainDB, Transaction } = require('../../utils/blockchain/index.js'); 4 | const blockchain = new BlockchainDB(); 5 | const config = require('../../../config.js'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const currency = require('../../utils/currency.js'); 9 | 10 | module.exports = { 11 | name: "blockchain-getbalance", 12 | description: "Get Balance By Address", 13 | cmd: ['getbalance', 'history', 'gethistory', 'balance'], 14 | menu: { 15 | label: 'blockchain', 16 | }, 17 | run: async ({ m, sock }) => { 18 | let id; 19 | if(m.quoted) { 20 | id = m.quoted.sender 21 | } else if (m.mentionedJid.length) { 22 | id = m.mentionedJid[0] 23 | } else if (m.body.arg) { 24 | id = m.body.arg 25 | } else { 26 | id = m.sender 27 | } 28 | 29 | const user = await db.user.get(id); 30 | if (!user) return m._reply(m.lang(msg).userNotFound); 31 | const history = await blockchain.getTransactionHistory(m.sender); 32 | 33 | let text = `*\`❖ Blockchain\`*\n`; 34 | text += `▷ Address/Id : ${id.split('@')[0]}\n` 35 | text += `▷ Balance : ${currency.format(await blockchain.getBalance(id))}\n\n`; 36 | text += `*\`❖ Transaction History\`*\n` 37 | text += String.fromCharCode(8206).repeat(4001) 38 | text +=history.map(tx => 39 | `▷ ${new moment(tx.timestamp).toLocaleString()}\n` + 40 | `▷ ${tx.type === 'mining_reward' ? 'Mining Reward' : 'Transfer'}\n` + 41 | `▷ ${tx.from === m.sender ? 'To: ' + tx.to : 'From: ' + tx.from}\n` + 42 | `▷ Total: ${currency.format(tx.amount)} coin\n` 43 | ).join('\n'); 44 | 45 | m._sendMessage(m.chat, { 46 | text: text, 47 | contextInfo: { 48 | mentionedJid: [], 49 | externalAdReply: { 50 | title: `❖ ${user.name}`, 51 | body: `▷ Blockchain`, 52 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 53 | sourceUrl: 'https://ilsya.my.id', 54 | mediaType: 1, 55 | // renderLargerThumbnail: true 56 | } 57 | } 58 | }, { quoted: m, ephemeralExpiration: m.ephemeral }) 59 | } 60 | } 61 | 62 | const msg = { 63 | id : { 64 | userNotFound: '> Pengguna tidak terdaftar.', 65 | } 66 | } -------------------------------------------------------------------------------- /src/command/blockchain/holders.js: -------------------------------------------------------------------------------- 1 | const { BlockchainDB, Transaction } = require('../../utils/blockchain/index.js'); 2 | const blockchain = new BlockchainDB(); 3 | const currency = require('../../utils/currency.js'); 4 | const db = require('../../utils/db.js'); 5 | const config = require('../../../config.js'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | module.exports = { 10 | name: "blockchain-holders", 11 | description: "Top Holders Blockchain", 12 | cmd: ['topholders', 'holders'], 13 | menu: { 14 | label: 'blockchain', 15 | }, 16 | run: async ({ m, sock }) => { 17 | 18 | const balances = await blockchain.getAllBalances(); 19 | const sortedHolders = Object.entries(balances) 20 | .sort(([,a], [,b]) => b - a) 21 | .slice(0, 20); 22 | 23 | let text = `*\`❖ Top ${sortedHolders.length} Holders Blockchain\`*\n\n`; 24 | text += sortedHolders.map(([address, balance], index) => { 25 | const user = db.user.get(address); 26 | if (user) { 27 | return `▷ \`${index + 1}\` ${user?.name || 'Unknown'} ${address.split('@')[0]}: ${currency.format(balance)} coin\n` 28 | } else if (address === 'unknown@s.whatsapp.net') { 29 | return `▷ \`${index + 1}\` ~Bank System~: ${currency.format(balance)} coin\n` 30 | } 31 | }).join('\n'); 32 | 33 | m._sendMessage(m.chat, { 34 | text: text, 35 | contextInfo: { 36 | mentionedJid: [], 37 | externalAdReply: { 38 | title: `❖ Top ${sortedHolders.length} Holders`, 39 | body: `▷ Blockchain`, 40 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 41 | sourceUrl: 'https://ilsya.my.id', 42 | mediaType: 1, 43 | // renderLargerThumbnail: true 44 | } 45 | } 46 | }, { quoted: m }) 47 | } 48 | } 49 | 50 | const msg = { 51 | id : { 52 | userNotFound: '> Pengguna tidak terdaftar.', 53 | } 54 | } -------------------------------------------------------------------------------- /src/command/blockchain/mine.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js'); 2 | const moment = require('../../utils/moment.js'); 3 | const config = require('../../../config.js'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const axios = require('axios'); 7 | 8 | module.exports = { 9 | name: "blockchain-mine", 10 | description: "Mining Blockchain", 11 | cmd: ['mining', 'mine', 'miner'], 12 | menu: { 13 | label: 'blockchain', 14 | }, 15 | limit: 15, 16 | run: async ({ m, sock }) => { 17 | const intervalTime = getRandomInRange(5, 20); // minutes 18 | try { 19 | let mine = db.blockchain.mine.get(m.sender); 20 | if (mine) return m._sendMessage(m.chat, { 21 | text: m.lang(msg).userExists.replace('{time}', moment(mine.remaining).diff(moment(), 'minutes')), 22 | contextInfo: { 23 | mentionedJid: [], 24 | externalAdReply: { 25 | title: `❖ Mining In Progress`, 26 | body: `▷ Blockchain`, 27 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 28 | sourceUrl: 'https://ilsya.my.id', 29 | mediaType: 1, 30 | // renderLargerThumbnail: true 31 | } 32 | } 33 | }) 34 | let expire = moment().add(intervalTime, 'minutes').valueOf(); 35 | db.blockchain.mine.put(m.sender, { 36 | m: m, 37 | address : m.sender, 38 | intervalTime, 39 | limit: m.commandLimit, 40 | remaining: expire 41 | }); 42 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 43 | 44 | m._sendMessage(m.chat, { 45 | text: m.lang(msg).success.replace('{time}', intervalTime), 46 | contextInfo: { 47 | mentionedJid: [], 48 | externalAdReply: { 49 | title: `❖ Mining In Progress`, 50 | body: `▷ Blockchain`, 51 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 52 | sourceUrl: 'https://ilsya.my.id', 53 | mediaType: 1, 54 | // renderLargerThumbnail: true 55 | } 56 | } 57 | }, { quoted: m }) 58 | } catch(error){ 59 | if(error.message == 'Maksimum supply tercapai!') return m._reply(m.lang(msg).maxSupply); 60 | m._reply(error.message); 61 | } 62 | } 63 | } 64 | 65 | function getRandomInRange(min, max) { 66 | return Math.floor(Math.random() * (max - min + 1)) + min; 67 | } 68 | 69 | const msg = { 70 | id: { 71 | success: 'Mining di mulai, estimasi selesai {time} menit.', 72 | userExists: 'Sedang ada progress yang berjalan, {time} menit lagi.', 73 | maxSupply: 'Maksimum supply tercapai!' 74 | }, 75 | en: { 76 | success: 'Mining started, Estimated time: {time} minutes.', 77 | userExists: 'Already mining, {time} minutes left.', 78 | maxSupply: 'Maximum supply reached!' 79 | } 80 | } -------------------------------------------------------------------------------- /src/command/blockchain/progress-mining.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js'); 2 | const moment = require('../../utils/moment.js'); 3 | const config = require('../../../config.js'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | module.exports = { 8 | name: "blockchain-mine-progress", 9 | description: "Mining Blockchain Progress", 10 | cmd: ['miningprogress', 'mineprogress', 'minerprogress'], 11 | menu: { 12 | label: 'blockchain', 13 | }, 14 | run: async ({ m, sock }) => { 15 | try { 16 | let mines = db.blockchain.mine.getRange() 17 | 18 | let text = `*\`❖ Mining Blockchain In Progress\`*\n\n` 19 | for (const mine of mines) { 20 | if (moment().valueOf() > mine.value.remaining) { 21 | text += `▷ *${mine.value.address.split('@')[0]}*: Mining Success\n` 22 | } else { 23 | text += `▷ *${mine.value.address.split('@')[0]}*: ${moment(mine.value.remaining).diff(moment(), 'minutes')} minutes\n` 24 | } 25 | } 26 | 27 | m._sendMessage(m.chat, { 28 | text: text, 29 | contextInfo: { 30 | mentionedJid: [], 31 | externalAdReply: { 32 | title: `❖ Mining In Progress`, 33 | body: `▷ Blockchain`, 34 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 35 | sourceUrl: 'https://ilsya.my.id', 36 | mediaType: 1, 37 | // renderLargerThumbnail: true 38 | } 39 | } 40 | }, { quoted: m }) 41 | } catch(error){ 42 | m._reply(error.message); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/command/blockchain/stats.js: -------------------------------------------------------------------------------- 1 | const { BlockchainDB, Transaction } = require('../../utils/blockchain/index.js'); 2 | const blockchain = new BlockchainDB(); 3 | const currency = require('../../utils/currency.js'); 4 | const moment = require('../../utils/moment.js'); 5 | const config = require('../../../config.js'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | module.exports = { 10 | name: "blockchain-stats", 11 | description: "All About Blockchain", 12 | cmd: ['blockchain', 'stats'], 13 | menu: { 14 | label: 'blockchain', 15 | }, 16 | run: async ({ m, sock }) => { 17 | const stats = await blockchain.getCoinStats(); 18 | let text = `*\`❖ Stats Blockchain\`*\n\n`; 19 | text += `▷ *Current Supply*: ${currency.format(stats.currentSupply)}\n` 20 | text += `▷ *Max Supply*: ${currency.format(stats.maxSupply)}\n` 21 | text += `▷ *Remaining Supply*: ${currency.format(stats.remainingSupply)}\n` 22 | text += `▷ *Current Reward Miner*: ${currency.format(stats.currentReward)}\n` 23 | text += `▷ *Block Mined*: ${currency.format(stats.blocksMined)}\n` 24 | text += `▷ *Blocks Until Halving*: ${currency.format(stats.blocksUntilHalving)}\n` 25 | text += `▷ *Bank System Balance*: ${currency.format(await blockchain.getBalance('unknown@s.whatsapp.net'))}\n\n` 26 | text += `▷ *Current Time*: ${moment().format('DD-MM-YYYY HH:mm:ss')}` 27 | m._sendMessage(m.chat, { 28 | text: text, 29 | contextInfo: { 30 | mentionedJid: [], 31 | externalAdReply: { 32 | title: `❖ Stats Nakiri Coin`, 33 | body: `▷ Blockchain`, 34 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 35 | sourceUrl: 'https://ilsya.my.id', 36 | mediaType: 1, 37 | // renderLargerThumbnail: true 38 | } 39 | } 40 | }, { quoted: m }) 41 | } 42 | } -------------------------------------------------------------------------------- /src/command/blockchain/transfer.js: -------------------------------------------------------------------------------- 1 | const { BlockchainDB, Transaction } = require('../../utils/blockchain/index.js'); 2 | const blockchain = new BlockchainDB(); 3 | const currency = require('../../utils/currency.js'); 4 | const db = require('../../utils/db.js'); 5 | const config = require('../../../config.js'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | module.exports = { 10 | name: "blockchain-transfer", 11 | description: "Transfer Blockchain", 12 | cmd: ['transfer', 'tfcoin', 'tf', 'tfblock'], 13 | menu: { 14 | label: 'blockchain', 15 | }, 16 | limit: 5, 17 | run: async ({ m, sock }) => { 18 | try { 19 | let id, balance, user = null; 20 | if (m.quoted) { 21 | id = m.quoted.sender; 22 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, ''); 23 | } else if (m.mentionedJid.length) { 24 | id = m.mentionedJid[0]; 25 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, ''); 26 | } else if (m.body.arg.split(' ')[1]) { 27 | id = m.body.arg.split(' ')[1]+'@s.whatsapp.net'; 28 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, ''); 29 | } else return m._reply(m.lang(msg).ex); 30 | 31 | if (id === m.sender) return m._reply(m.lang(msg).lucu); 32 | if (!Number(balance) || balance.trim() == '') return m._reply(m.lang(msg).ex); 33 | if (Number(balance) < 1) return m._reply(m.lang(msg).min); 34 | if (Number(balance) > 50000000) return m._reply(m.lang(msg).max); 35 | 36 | if (id != 'unknown@s.whatsapp.net') { 37 | user = db.user.get(id); 38 | if(!user) return m._reply(m.lang(msg).userNotFound); 39 | } 40 | 41 | const result = await blockchain.transfer(m.sender, id, Number(balance)); 42 | let text = `*\`❖ Transfer Blockchain Success\`*\n\n`; 43 | text += `▷ *ID Transaction*: ${result.txId}\n` 44 | text += `▷ *Amount*: ${currency.format(result.amount)} coin\n` 45 | text += `▷ *To*: ${id.split('@')[0] == 'unknown' ? 'Anonymous' : user.name }\n` 46 | text += `▷ *Limit used*: ${m.commandLimit}` 47 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 48 | m._sendMessage(m.chat, { 49 | text: text, 50 | contextInfo: { 51 | mentionedJid: [ result.to ], 52 | externalAdReply: { 53 | title: `❖ Transfer Coin`, 54 | body: `▷ Blockchain`, 55 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 56 | sourceUrl: 'https://ilsya.my.id', 57 | mediaType: 1, 58 | // renderLargerThumbnail: true 59 | } 60 | } 61 | }, { quoted: m }) 62 | } catch (error) { 63 | if(error.message == 'Saldo tidak cukup!') return m._reply(m.lang(msg).saldoNotEnough); 64 | m._reply(error.message); 65 | } 66 | } 67 | } 68 | 69 | const msg = { 70 | id: { 71 | ex: 'Penggunaan:\n▷ {prefix}tf `nominal` `@mention`\n▷ Balas pesan dengan caption {prefix}tf `nominal`', 72 | max: 'Maksimal sekali transfer 50.000.000 coin.', 73 | min: 'Minimal 1 coin.', 74 | userNotFound: 'Pengguna tidak terdaftar.', 75 | saldoNotEnough: 'Balance kamu tidak cukup.', 76 | lucu: 'Jangan lucu lah. ngirim ke diri sendiri.' 77 | }, 78 | en: { 79 | ex: 'Usage:\n▷ {prefix}tf `nominal` `@mention`\n▷ Reply to a message with caption {prefix}tf `nominal`', 80 | max: 'Maximal transfer 50.000.000 coin.', 81 | min: 'Minimal 1 coin.', 82 | userNotFound: 'User not found.', 83 | saldoNotEnough: 'Your balance is not enough.', 84 | lucu: 'Don\'t be funny. send to yourself.' 85 | } 86 | } -------------------------------------------------------------------------------- /src/command/downloader/facebook.js: -------------------------------------------------------------------------------- 1 | const { fbdl } = require('../../utils/scraper.js') 2 | const db = require('../../utils/db.js') 3 | 4 | module.exports = { 5 | name: "downloader-facebook", 6 | description: "Download Video From Facebook", 7 | cmd: ['fb', 'facebook', 'fbdl'], 8 | menu: { 9 | label: 'downloader', 10 | example: 'url' 11 | }, 12 | limit: 1, 13 | run: async ({ m, sock }) => { 14 | if (!m.body.arg) return m._reply(m.lang(msg).ex) 15 | 16 | const url = m.body.arg; 17 | if (!/^https?:\/\/(?:www\.)?(facebook|fb|instagram)\.com\/.+$/.test(url)) return m._reply(m.lang(msg).urlInvalid) 18 | try { 19 | m._react(m.key, '🔍') 20 | const res = await fbdl(url); 21 | const bestQuality = res.data[0]; 22 | const caption = `- *Resolution*: ${bestQuality.resolution}\n- *Limit used*: ${m.commandLimit}` 23 | await m._sendMessage(m.chat, { 24 | caption: caption, 25 | video: { url: bestQuality.url } 26 | }, { quoted: m }) 27 | m._react(m.key, '✅') 28 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 29 | } catch (error) { 30 | m._react(m.key, '❌') 31 | m._reply(m.lang(msg).failed) 32 | } 33 | } 34 | } 35 | 36 | const msg = { 37 | id: { 38 | ex: '*Penggunaan*: {prefix}fb ``', 39 | urlInvalid: 'URL tidak valid', 40 | failed: 'Gagal mengunduh video.' 41 | }, 42 | en: { 43 | ex: '*Usage*: {prefix}fb ``', 44 | urlInvalid: 'URL not valid', 45 | failed: 'Failed to download video.' 46 | } 47 | } -------------------------------------------------------------------------------- /src/command/downloader/git.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios'); 2 | const mime = require('mime-types'); 3 | const db = require('../../utils/db.js'); 4 | 5 | module.exports = { 6 | name: "downloader-gitclone", 7 | description: "Git Clone Repo Github", 8 | cmd: ['git', 'gitclone'], 9 | menu: { 10 | label: 'downloader', 11 | example: 'url' 12 | }, 13 | limit: 1, 14 | run: async ({ m, sock }) => { 15 | if (!m.body.arg) return m._reply(m.lang(msg).ex) 16 | 17 | const url = m.body.arg; 18 | const user = url.split('/')[3]; 19 | const repo = url.split('/').pop().split('.git')[0]; 20 | if(!user || !repo) return m._reply(m.lang(msg).urlInvalid) 21 | 22 | m._react(m.key, '🔍') 23 | axios.get(`https://api.github.com/repos/${user}/${repo}/zipball`, { responseType: 'arraybuffer' }).then(async(res) => { 24 | await m._sendMessage(m.chat, { 25 | document: res.data, 26 | fileName: `${repo}.zip`, 27 | mimetype: mime.lookup(`${repo}.zip`), 28 | }, { quoted: m }) 29 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 30 | m._react(m.key, '✅') 31 | }).catch(e => { 32 | m._react(m.key, '❌') 33 | m._reply(e.message) 34 | }) 35 | } 36 | } 37 | 38 | const msg = { 39 | id: { 40 | ex: 'penggunaan: {prefix}git ``', 41 | urlInvalid: 'URL tidak valid' 42 | }, 43 | en: { 44 | ex: 'usage: {prefix}git ``', 45 | urlInvalid: 'URL not valid' 46 | } 47 | } -------------------------------------------------------------------------------- /src/command/downloader/instagram.js: -------------------------------------------------------------------------------- 1 | const { fbdl } = require('../../utils/scraper.js') 2 | const db = require('../../utils/db.js') 3 | 4 | module.exports = { 5 | name: "downloader-instagram", 6 | description: "Download Video From Instagram", 7 | cmd: ['ig', 'instagram', 'igdl'], 8 | menu: { 9 | label: 'downloader', 10 | example: 'url' 11 | }, 12 | limit: 1, 13 | run: async ({ m, sock }) => { 14 | if (!m.body.arg) return m._reply(m.lang(msg).ex) 15 | 16 | const url = m.body.arg; 17 | if (!/^https?:\/\/(?:www\.)?(facebook|fb|instagram)\.com\/.+$/.test(url)) return m._reply(m.lang(msg).urlInvalid) 18 | try { 19 | m._react(m.key, '🔍') 20 | const res = await fbdl(url); 21 | const bestQuality = res.data[0]; 22 | await m._sendMessage(m.chat, { 23 | video: { url: bestQuality.url } 24 | }, { quoted: m }) 25 | m._react(m.key, '✅') 26 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 27 | } catch (error) { 28 | m._react(m.key, '❌') 29 | m._reply(m.lang(msg).failed) 30 | } 31 | } 32 | } 33 | 34 | const msg = { 35 | id: { 36 | ex: '*Penggunaan*: {prefix}ig ``', 37 | urlInvalid: 'URL tidak valid', 38 | failed: 'Gagal mengunduh video.' 39 | }, 40 | en: { 41 | ex: '*Usage*: {prefix}ig ``', 42 | urlInvalid: 'URL not valid', 43 | failed: 'Failed to download video.' 44 | } 45 | } -------------------------------------------------------------------------------- /src/command/downloader/tiktok.js: -------------------------------------------------------------------------------- 1 | const { ttdl } = require('../../utils/scraper.js') 2 | const db = require('../../utils/db.js') 3 | 4 | module.exports = { 5 | name: "downloader-tiktok", 6 | description: "Download Video From Tiktok", 7 | cmd: ['tt', 'tiktok', 'ttdl'], 8 | menu: { 9 | label: 'downloader', 10 | example: 'url' 11 | }, 12 | limit: 1, 13 | run: async ({ m, sock }) => { 14 | if (!m.body.arg) return m._reply(m.lang(msg).ex) 15 | const url = m.body.arg; 16 | if (!/^https?:\/\/(?:[a-z]+\.)?(tiktok)\.com\/.+$/.test(url)) return m._reply(m.lang(msg).urlInvalid); 17 | try { 18 | m._react(m.key, '🔍') 19 | const res = await ttdl(url); 20 | const caption = `*Title*: ${res.title}\n*Views*: ${res.views}\n*Like*: ${res.like}\n*Resolution*: HD No Watermark\n*Limit used*: ${m.commandLimit}` 21 | await m._sendMessage(m.chat, { 22 | caption: caption, 23 | video: { url: res.video } 24 | }, { quoted: m }) 25 | m._react(m.key, '✅') 26 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 27 | } catch (error) { 28 | m._react(m.key, '❌') 29 | m._reply(m.lang(msg).failed) 30 | } 31 | } 32 | } 33 | 34 | const msg = { 35 | id: { 36 | ex: '*Penggunaan*: {prefix}tiktok ``', 37 | urlInvalid: 'URL tidak valid', 38 | failed: 'Gagal mengunduh video.' 39 | }, 40 | en: { 41 | ex: '*Usage*: {prefix}tiktok ``', 42 | urlInvalid: 'URL not valid', 43 | failed: 'Failed to download video.' 44 | } 45 | } -------------------------------------------------------------------------------- /src/command/downloader/yt.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios'); 2 | const db = require('../../utils/db.js'); 3 | 4 | module.exports = { 5 | name: "downloader-yt", 6 | description: "Youtube Downloader", 7 | cmd: ['yt', 'ytdl', 'ytmp4'], 8 | menu: { 9 | label: 'downloader', 10 | example: 'url' 11 | }, 12 | limit: 1, 13 | run: async ({ m, sock }) => { 14 | if (!m.body.arg) return m._reply(m.lang(msg).ex) 15 | if (!/^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/(watch\?v=|embed\/|v\/|.+\?v=)?([^&\s]{11})/.test(m.body.arg)) return m._reply(m.lang(msg).urlInvalid) 16 | const url = m.body.arg; 17 | 18 | try { 19 | m._react(m.key, '🔍') 20 | axios.get('https://deliriussapi-oficial.vercel.app/download/ytmp4?url='+ encodeURIComponent(url)).then(async(res) => { 21 | if(!res?.data) throw new Error(m.lang(msg).failed) 22 | await m._sendMessage(m.chat, { 23 | video: { 24 | url: res.data.data.download.url 25 | } 26 | }, { quoted: m }) 27 | m._react(m.key, '✅') 28 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 29 | }).catch((error) => { 30 | m._react(m.key, '❌') 31 | m._reply(m.lang(msg).failed) 32 | }) 33 | }catch (error) { 34 | m._reply(error.message) 35 | } 36 | 37 | } 38 | } 39 | 40 | 41 | const msg = { 42 | id: { 43 | ex: 'penggunaan: {prefix}yt `url`', 44 | urlInvalid: 'URL tidak valid', 45 | failed: 'Gagal mengunduh video.' 46 | }, 47 | en: { 48 | ex: 'usage: {prefix}yt `url`', 49 | urlInvalid: 'URL not valid', 50 | failed: 'Failed to download video.' 51 | } 52 | } -------------------------------------------------------------------------------- /src/command/downloader/ytmp3.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios'); 2 | const db = require('../../utils/db.js'); 3 | 4 | module.exports = { 5 | name: "downloader-ytmp3", 6 | description: "Youtube Downloader Mp3", 7 | cmd: ['ytmp3', 'play'], 8 | menu: { 9 | label: 'downloader', 10 | example: 'url' 11 | }, 12 | limit: 1, 13 | run: async ({ m, sock }) => { 14 | if (!m.body.arg) return m._reply(m.lang(msg).ex) 15 | if (!/^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/(watch\?v=|embed\/|v\/|.+\?v=)?([^&\s]{11})/.test(m.body.arg)) return m._reply(m.lang(msg).urlInvalid) 16 | const url = m.body.arg; 17 | 18 | try { 19 | m._react(m.key, '🔍') 20 | axios.get('https://api.nyxs.pw/dl/yt-direct?url='+ encodeURIComponent(url)).then(async(res) => { 21 | if(!res?.data?.result?.urlAudio) return m._reply(m.lang(msg).failed) 22 | await m._sendMessage(m.chat, { 23 | audio: { 24 | url: res.data.result.urlAudio 25 | }, 26 | mimetype: 'audio/mp4' 27 | }, { quoted: m }) 28 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 29 | m._react(m.key, '✅') 30 | }).catch((error) => { 31 | m._react(m.key, '❌') 32 | m._reply(m.lang(msg).failed) 33 | }) 34 | }catch (error) { 35 | m._react(m.key, '❌') 36 | m._reply(error.message) 37 | } 38 | 39 | } 40 | } 41 | 42 | const msg = { 43 | id: { 44 | ex: 'penggunaan: {prefix}ytmp3 `url`', 45 | urlInvalid: 'URL tidak valid', 46 | failed: 'Gagal mengunduh audio.' 47 | }, 48 | en: { 49 | ex: 'usage: {prefix}ytmp3 `url`', 50 | urlInvalid: 'URL not valid', 51 | failed: 'Failed to download audio.' 52 | } 53 | } -------------------------------------------------------------------------------- /src/command/fun/tebak-angka.js: -------------------------------------------------------------------------------- 1 | const exp = require('../../utils/exp.js'); 2 | 3 | module.exports = { 4 | name: "fun-tebak-angka", 5 | description: "Tebak Angka", 6 | cmd: ['angka', 'number', 'tebakangka'], 7 | menu: { 8 | label: 'fun', 9 | example: '<1-10>' 10 | }, 11 | run: async ({ m, sock }) => { 12 | const number = m.body.arg.replace(/[^0-9]/g, ''); 13 | if(!number) return m._reply(m.lang(msg).ex); 14 | let random = Math.floor(Math.random() * 10) + 1; 15 | if(number < 1 || number > 10) return m._reply(m.lang(msg).minamx); 16 | 17 | let text = `\`${m.lang(msg).title}\`\n\n` 18 | text += `> Angka Kamu : ${number}\n` 19 | text += `> Angka Bot : ${random}\n\n` 20 | text += `_${m.lang(msg).answ}_` 21 | exp.add(m.sender, exp.random(1, 5)); 22 | m._reply(text) 23 | } 24 | } 25 | 26 | const msg = { 27 | id: { 28 | ex: 'penggunaan: {prefix}angka `1-10`', 29 | minmax: 'Angka harus di antara `1-10`', 30 | title: 'Tebak Angka', 31 | answ: 'Apakah Angkamu Dengan Bot Sama?', 32 | }, 33 | en: { 34 | ex: 'usage: {prefix}number `1-10`', 35 | minamx: 'Number must be between `1-10`', 36 | title: 'Guess Number', 37 | answ: 'Is your number with the bot same?', 38 | } 39 | } -------------------------------------------------------------------------------- /src/command/games/blackjack.js: -------------------------------------------------------------------------------- 1 | const { 2 | bjMap, 3 | createDeck, 4 | formatCard, 5 | formatHand, 6 | calculateHandValue, 7 | } = require('../../utils/games/blackjack.js'); 8 | const currency = require('../../utils/currency.js'); 9 | 10 | const exp = require('../../utils/exp.js'); 11 | 12 | module.exports = { 13 | name : "game-blackjack", 14 | description : "Game Blackjack", 15 | cmd : ['blackjack', 'bj'], 16 | menu : { 17 | label : 'games', 18 | example : '' 19 | }, 20 | run : async({ m, sock }) => { 21 | if(m.fromMe) return; 22 | if(bjMap.has(m.sender)) return m._reply(m.lang(msg).exist); 23 | if(!m.body.arg) return m._reply(m.lang(msg).ex); 24 | 25 | let bet = m.body.arg.replace(/[^0-9]/g, ''); 26 | if(m.body.arg == 'all') bet = 500000; 27 | if(bet < 5000) return m._reply(m.lang(msg).minbet); 28 | if(bet > 500000) return m._reply(m.lang(msg).maxbet); 29 | if (currency.subtract(m.db.user.balance, bet) === false) return m._reply(m.lang(msg).balance); 30 | currency.updateBalanceUser(m.sender, currency.subtract(m.db.user.balance, bet)); 31 | 32 | const deck = createDeck(); 33 | const playerHand = [deck.pop(), deck.pop()]; 34 | const dealerHand = [deck.pop(), deck.pop()]; 35 | 36 | let response = `_*${m.db.user.name}*, you bet *${currency.format(bet)}* to play blackjack._\n\n`; 37 | response += `> *Your hand*: _${formatHand(playerHand)}_ *\`[${calculateHandValue(playerHand)}]\`*\n`; 38 | response += `> *Dealer's visible card*: _${formatCard(dealerHand[0])}_ *\`[${calculateHandValue(dealerHand)}+?]\`*\n\n`; 39 | response += m.lang(msg).desc; 40 | 41 | const sent = await m._sendMessage(m.chat, { text: response }, { quoted: m }); 42 | exp.add(m.sender, exp.random(1, 10)); 43 | bjMap.set(m.sender, { 44 | deck, 45 | playerHand, 46 | dealerHand, 47 | status: 'playing', 48 | bet: bet, 49 | messageKey : sent.key, 50 | }); 51 | } 52 | } 53 | 54 | const msg = { 55 | id: { 56 | ex: 'Penggunaan {prefix}bj ', 57 | exist: 'Permainan Blackjack sebelumnya sedang berlangsung.', 58 | balance: 'Saldo kamu tidak cukup.', 59 | minbet: 'Minimal 5.000', 60 | maxbet: 'Maximal 500.000', 61 | desc: '```Tipe``` *`hit`* ```untuk mengambil kartu lain atau``` *`stand`* ```untuk mempertahankan kartu Anda saat ini.```' 62 | }, 63 | en: { 64 | ex: 'Usage: {prefix}bj ', 65 | exist: 'Blackjack game is already in progress.', 66 | balance: 'Your balance is not enough.', 67 | minbet: 'Minimal 5.000', 68 | maxbet: 'Maximal 500.000', 69 | desc: '```Type``` *`hit`* ```to take another card or``` *`stand`* ```to keep your current hand.```' 70 | } 71 | } -------------------------------------------------------------------------------- /src/command/games/tictactoe.js: -------------------------------------------------------------------------------- 1 | const tic = require('../../utils/games/tictactoe.js'); 2 | const currency = require('../../utils/currency.js'); 3 | const db = require('../../utils/db.js'); 4 | const exp = require('../../utils/exp.js'); 5 | 6 | module.exports = { 7 | name : "game-tictactoe", 8 | description : "Tic Tac Toe", 9 | cmd : ['tictactoe', 'tic', 'ttt'], 10 | menu : { 11 | label : 'games', 12 | example : 'balance ' 13 | }, 14 | run : async({ m, sock }) => { 15 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 16 | if(tic.ticMap.has(m.chat)) return m._reply(m.lang(msg).already) 17 | let bet = m.body.arg.split(' ')[0], 18 | player1 = m.sender, 19 | player2 = m.mentionedJid[0] || 'ai'; 20 | if(!bet || !player1 || !player2) return m._reply(m.lang(msg).ex); 21 | if(bet == 'all') { 22 | bet = 500000 23 | } else { 24 | bet = bet.replace(/[^0-9]/g, '') 25 | } 26 | if(bet < 5000) return m._reply(m.lang(msg).minbet); 27 | if(bet > 500000) return m._reply(m.lang(msg).maxbet); 28 | 29 | if(player2 == 'ai') { 30 | if (currency.subtract(m.db.user.balance, bet) === false) return m._reply(m.lang(msg).balance.replace('{name}', '')); 31 | currency.updateBalanceUser(m.sender, currency.subtract(m.db.user.balance, bet)); 32 | const gameState = tic.createGame(m.chat, player1, 'ai@tictactoe', true, bet); 33 | exp.add(m.sender, exp.random(1, 10)); 34 | await m._sendMessage(m.chat, { 35 | text: `TicTacToe Vs AI!\n\n${gameState.board}\n\n\@${player1.split('@')[0]} turn!`, 36 | mentions: [player1] 37 | }); 38 | } else { 39 | const opponent = m.mentionedJid[0]; 40 | if (!opponent) return m._reply(m.lang(msg).ex); 41 | const dbp2 = db.user.get(opponent); 42 | if(!dbp2) return m._reply(m.lang(msg).unreg); 43 | 44 | // cek saldo player1 45 | if (currency.subtract(m.db.user.balance, bet) === false) return m._reply(m.lang(msg).balance.replace('{name}', m.db.user.name + ' ')); 46 | // cek saldo player2 47 | if (currency.subtract(dbp2.balance, bet) === false) return m._reply(m.lang(msg).balance.replace('{name}', dbp2.name + ' ')); 48 | 49 | tic.createGame(m.chat, m.sender, opponent, false, bet); 50 | 51 | await m._sendMessage(m.chat, { 52 | text: m.lang(msg).reqApprove.replace('{player1}', m.sender.split('@')[0]).replace('{player2}', opponent.split('@')[0]).replace('{balance}', currency.format(bet)), 53 | mentions: [opponent, m.sender] 54 | }); 55 | } 56 | } 57 | } 58 | 59 | const msg = { 60 | id: { 61 | ex: 'Cara bermain, tentukan ingin lawan siapa.\n▷ Lawan AI: {prefix}tic `balance` `ai`\n▷ Lawan orang: {prefix}tic `balance` `@mention`\n\nKeterangan:\n- *balance*: Jumlah taruhan.\n- *@mention*: Tag anggota yang ingin di lawan.\n', 62 | minbet: 'Jumlah taruhan minimal 5000.', 63 | maxbet: 'Jumlah taruhan maksimal 500.000.', 64 | balance: 'Saldo {name}tidak mencukupi.', 65 | already: 'Ada permainan sedang berlangsung.\nSelesaikan permainan sebelumnya terlebih dahulu.\nAtau ketik endgame untuk mengakhiri permainan.', 66 | unreg: 'Orang yang anda tantang belum terdaftar.\nSilahkan minta orang yang anda tantang mengetik {prefix}reg `nama`, jika sudah silahkan anda tantang kembali.', 67 | reqApprove: '@{player2}, kamu ditantang bermain TicTacToe oleh @{player1} dengan taruhan {balance}.\nKetik `accept` untuk menerima, atau `reject` untuk menolak.', 68 | }, 69 | en: { 70 | ex: 'Usage: {prefix}tic `balance` `@mention` or {prefix}tic `balance` `ai`\n\nNote:\n- *balance*: Bet amount.\n- *@mention*: Mention the player you want to play against.\n', 71 | minbet: 'Minimal bet 5000.', 72 | maxbet: 'Maximal bet 500.000.', 73 | balance: 'Balance {name} not enough.', 74 | already: 'There is a game in progress.\nFinish the previous game first.\nOr type endgame to finish the game.', 75 | unreg: 'The person you challenged is not registered.\nPlease ask the person you challenged to type {prefix}reg `name`, if already please challenge again.', 76 | reqApprove: '@{player2}, you have challenged TicTacToe game by @{player1} with bet {balance}.\nType `accept` to accept, or `reject` to reject.', 77 | } 78 | } -------------------------------------------------------------------------------- /src/command/group/add.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "group-add", 3 | description : "Add Participant From Group", 4 | cmd : ['add'], 5 | menu : { 6 | label : 'group', 7 | example : 'number' 8 | }, 9 | run : async({ m, sock }) => { 10 | try { 11 | if(!m.isGroup) return 12 | if(!m.isGroup.botIsAdmin) return 13 | if(!m.isGroup.senderIsAdmin) return 14 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 15 | let number = m.body.arg 16 | await sock.groupParticipantsUpdate(m.chat, [`${number}@s.whatsapp.net`], "add") 17 | } catch(error) { 18 | await m._reply(error.message) 19 | } 20 | } 21 | } 22 | 23 | const msg = { 24 | id: { 25 | ex: 'penggunaan: {prefix}add `nomor`' 26 | }, 27 | en: { 28 | ex: 'usage: {prefix}add `number`' 29 | } 30 | } -------------------------------------------------------------------------------- /src/command/group/antilink.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | 3 | module.exports = { 4 | name : "group-antilink", 5 | description : "Menghandle fitur antilink di group", 6 | cmd : ['antilink'], 7 | menu : { 8 | label : 'group', 9 | example : '' 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.isGroup) return 14 | if(!m.isGroup.botIsAdmin) return 15 | if(!m.isGroup.senderIsAdmin) return 16 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 17 | 18 | if(m.body.arg == 'enable' || m.body.arg == 'on' || m.body.arg == 'true') { 19 | await db.update(db.group, m.isGroup.groupMetadata.id, { antilink: true }) 20 | await m._reply(m.lang(msg).active) 21 | } else if(m.body.arg == 'disable' || m.body.arg == 'off' || m.body.arg == 'false') { 22 | await db.update(db.group, m.isGroup.groupMetadata.id, { antilink: false }) 23 | await m._reply(m.lang(msg).inactive) 24 | } else { 25 | await m._reply(m.lang(msg).ex) 26 | } 27 | } catch(error) { 28 | await m._reply(error.message) 29 | } 30 | } 31 | } 32 | 33 | const msg = { 34 | id: { 35 | ex: 'Penggunaan: {prefix}antilink ``\n\nContoh:\n▷ {prefix}antilink enable → Mengaktifkan fitur antilink.\n▷ {prefix}antilink disable → Menonaktifkan fitur antilink.', 36 | active: 'Antilink telah diaktifkan di grup ini.', 37 | inactive: 'Antilink telah dinonaktifkan untuk semua anggota.' 38 | }, 39 | en: { 40 | ex: 'Usage: {prefix}antilink ``\n\nExample:\n▷ {prefix}antilink enable → Activates the antilink feature.\n▷ {prefix}antilink disable → Deactivates the antilink feature.', 41 | active: 'Antilink has been activated in this group.', 42 | inactive: 'Antilink has been disabled for all members.' 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/command/group/del.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "group-del-message", 3 | description : "Delete message from group", 4 | cmd : ['del', 'delete'], 5 | menu : { 6 | label : 'group', 7 | example : 'reply' 8 | }, 9 | run : async({ m, sock }) => { 10 | try { 11 | if(!m.isGroup) return 12 | if(!m.isGroup.botIsAdmin) return 13 | if(!m.isGroup.senderIsAdmin) return 14 | if(!m.quoted) return m._reply(m.lang(msg).ex) 15 | // hapus pesan yang di reply 16 | await sock.sendMessage(m.chat, { delete: m.quoted.key }) 17 | } catch(error) { 18 | await m._reply(error.message) 19 | } 20 | } 21 | } 22 | 23 | const msg = { 24 | id: { 25 | ex: 'reply message yang ingin di hapus' 26 | }, 27 | en: { 28 | ex: 'reply message you want to delete' 29 | } 30 | } -------------------------------------------------------------------------------- /src/command/group/group-info.js: -------------------------------------------------------------------------------- 1 | const util = require('util'); 2 | 3 | module.exports = { 4 | name : "group-info", 5 | description : "Show Group Info", 6 | cmd : ['groupinfo', 'ginfo'], 7 | menu : { 8 | label : 'group', 9 | }, 10 | run : async({ m, sock }) => { 11 | try { 12 | if(!m.isGroup) return 13 | if(!m.isGroup.botIsAdmin) return 14 | if(!m.isGroup.senderIsAdmin) return 15 | let text = `*Group Info* ${m.isGroup.groupMetadata.subject} \n\n` 16 | text += `*ID*: ${m.isGroup.groupMetadata.id} \n` 17 | text += `*Group Name*: ${m.isGroup.groupMetadata.subject} \n` 18 | text += `*Group Owner*: ${m.isGroup.groupMetadata?.owner?.split('@')[0] || 'Unknown'} \n` 19 | text += `*isCommunity*: ${m.isGroup.groupMetadata.isCommunity ? 'Yes' : 'No'} \n` 20 | text += `*joinApprovalMode*: ${m.isGroup.groupMetadata.joinApprovalMode ? 'Yes' : 'No'} \n` 21 | text += `*memberAddMode*: ${m.isGroup.groupMetadata.memberAddMode ? 'Yes' : 'No'} \n` 22 | text += `*ephemeralMessage*: ${m.isGroup.groupMetadata.ephemeralDuration ? 'Yes' : 'No'} \n` 23 | text += `*Participants*: ${m.isGroup.groupMetadata.participants.length} Members \n\n` 24 | text += String.fromCharCode(8206).repeat(4001) 25 | text += `*Info Settings Bot*: \n\n` 26 | text += util.format(m.db.group) 27 | m._reply(text) 28 | } catch(error) { 29 | await m._reply(error.message) 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/command/group/hidetag.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "group-hidetag", 3 | description : "Hidetag Group", 4 | cmd : ['hidetag'], 5 | menu : { 6 | label : 'group', 7 | }, 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.isGroup) return 11 | if(!m.isGroup.botIsAdmin) return 12 | if(!m.isGroup.senderIsAdmin) return 13 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 14 | let mentions = m.isGroup.groupMetadata.participants.map(v => v.id) 15 | await m._sendMessage(m.chat, { text: m.body.arg }, { mentions: mentions }) 16 | } catch(error) { 17 | await m._reply(error.message) 18 | } 19 | } 20 | } 21 | 22 | const msg = { 23 | id: { 24 | ex: 'penggunaan: {prefix}hidetag `text`' 25 | }, 26 | en: { 27 | ex: 'usage: {prefix}hidetag `text`' 28 | } 29 | } -------------------------------------------------------------------------------- /src/command/group/kick.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "group-kick", 3 | description : "Kick Participant From Group", 4 | cmd : ['kick'], 5 | menu : { 6 | label : 'group', 7 | example : 'reply or mention' 8 | }, 9 | run : async({ m, sock }) => { 10 | try { 11 | if(!m.isGroup) return 12 | if(!m.isGroup.botIsAdmin) return 13 | if(!m.isGroup.senderIsAdmin) return 14 | if(!m.quoted && !m.mentionedJid.length) return m._reply(m.lang(msg).ex) 15 | 16 | if(m.quoted) await sock.groupParticipantsUpdate(m.chat, [m.quoted.sender], "remove") 17 | for (let i of m?.mentionedJid || []) { 18 | await sock.groupParticipantsUpdate(m.chat, [i], "remove") 19 | } 20 | } catch(error) { 21 | await m._reply(error.message) 22 | } 23 | } 24 | } 25 | 26 | const msg = { 27 | id: { 28 | ex: 'Penggunaan:\n\n1. *Balas Pesan*: Balas pesan anggota yang ingin di-kick dengan perintah ini.\n2. **Sebut Anggota**: Sebut (mention) anggota yang ingin di-kick dengan perintah ini.', 29 | }, 30 | en: { 31 | ex: 'Usage:\n\n1. *Reply to Message*: Reply to the message of the member you want to kick with this command.\n2. **Mention Member**: Mention the member you want to kick with this command.', 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/command/group/leaderboard.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | 3 | module.exports = { 4 | name : "group-leaderboard", 5 | description : "Menampilkan leaderboard member group", 6 | cmd : ['leaderboard', 'top'], 7 | menu : { 8 | label : 'group', 9 | example : 'range' 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.isGroup) return 14 | if(!m.isGroup.senderIsAdmin) return 15 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 16 | 17 | const leaderboard = Object.entries(m.db?.group?.member_activity) 18 | .sort(([, a], [, b]) => b - a) 19 | .slice(0, m.body.arg) 20 | .map(([member, activity], index) => ({ 21 | rank: index + 1, 22 | member, 23 | activity 24 | })); 25 | let text; 26 | 27 | text = `*\`❖ Leaderboard Group\`*\n\n` 28 | for (const { rank, member, activity } of leaderboard) { 29 | text += `▷ *\`${rank}\`* @${member.split('@')[0]} - *${activity}*\n` 30 | } 31 | 32 | await m._sendMessage(m.chat, { 33 | text, 34 | mentions: [...leaderboard.map(({ member }) => member)] 35 | }, { quoted: m }); 36 | 37 | } catch(error) { 38 | await m._reply(error.message) 39 | } 40 | } 41 | } 42 | 43 | const msg = { 44 | id: { 45 | ex: 'Penggunaan: {prefix}leaderboard `range`\n\n*Keterangan:*\n- *range*: jumlah yang ingin di tampilkan.', 46 | }, 47 | en: { 48 | ex: 'Usage: {prefix}leaderboard `range`\n\n*Description:*\n- *range*: The range you want to keep.', 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/command/group/link.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "group-link", 3 | description : "Get Link Group", 4 | cmd : ['gclink'], 5 | menu : { 6 | label : 'group' 7 | }, 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.isGroup) return 11 | if(!m.isGroup.botIsAdmin) return 12 | const link = `https://chat.whatsapp.com/${await sock.groupInviteCode(m.chat)}` 13 | await m._reply(link) 14 | } catch(error) { 15 | await m._reply(error.message) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/command/group/mode.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | 3 | module.exports = { 4 | name : "group-mode", 5 | description : "Mengatur respon bot di group", 6 | cmd : ['gmode'], 7 | menu : { 8 | label : 'group', 9 | example : '' 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.isGroup) return 14 | if(!m.isGroup.botIsAdmin) return 15 | if(!m.isGroup.senderIsAdmin) return 16 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 17 | 18 | if(m.body.arg == 'adminonly' || m.body.arg == 'admin') { 19 | await db.update(db.group, m.isGroup.groupMetadata.id, { mode: 'admin-only' }) 20 | await m._reply(m.lang(msg).active) 21 | } else if(m.body.arg == 'all') { 22 | await db.update(db.group, m.isGroup.groupMetadata.id, { mode: 'all' }) 23 | await m._reply(m.lang(msg).inactive) 24 | } else { 25 | await m._reply(m.lang(msg).ex) 26 | } 27 | } catch(error) { 28 | await m._reply(error.message) 29 | } 30 | } 31 | } 32 | 33 | const msg = { 34 | id: { 35 | ex: 'Penggunaan: {prefix}gmode ``\n\n*Keterangan:*\n- *admin*: Bot hanya akan merespons perintah dari anggota yang memiliki status admin.\n- *all*: Bot akan merespons perintah dari semua anggota grup.', 36 | active: 'Bot telah diatur untuk hanya merespons kepada admin saja.', 37 | inactive: 'Bot telah diatur untuk merespons kepada semua anggota.' 38 | }, 39 | en: { 40 | ex: 'Usage: {prefix}gmode ``\n\n*Description:*\n- *admin*: Bot will only respond to commands from members with admin status.\n- *all*: Bot will respond to commands from all group members.', 41 | active: 'Bot has been set to only respond to admin.', 42 | inactive: 'Bot has been set to respond to all members.' 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/command/group/random-kick.js: -------------------------------------------------------------------------------- 1 | const { delay } = require('@whiskeysockets/baileys') 2 | 3 | module.exports = { 4 | name : "group-random-kcik", 5 | description : "Random Kick Participant From Group", 6 | cmd : ['randomkick', 'rkick'], 7 | menu : { 8 | label : 'group', 9 | }, 10 | run : async({ m, sock }) => { 11 | try { 12 | if(!m.isGroup) return 13 | if(!m.isGroup.botIsAdmin) return 14 | if(!m.isGroup.senderIsAdmin) return 15 | if(!m.db.group?.activity_record) return m._reply(m.lang(msg).inactive) 16 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 17 | let [ score, member ] = m.body.arg.split(' ') 18 | if(!member || !score) return m._reply(m.lang(msg).ex) 19 | 20 | score = parseInt(score) 21 | member = parseInt(member) 22 | if(member < 1) return m._reply(m.lang(msg).ex) 23 | 24 | let kicked = 0 25 | let mmm = 0; 26 | if(score == 0){ 27 | let members = m.isGroup.groupMetadata.participants.filter(v => v.admin !== 'superadmin' && v.admin !== 'admin') 28 | members = members.filter(v => !m.db.group.member_activity[v.id] ) 29 | mmm = members.length 30 | for(let i = 0; i < member; i++){ 31 | let random = Math.floor(Math.random() * members.length) 32 | if(mmm == 0) break 33 | await delay(1000) 34 | await sock.groupParticipantsUpdate(m.chat, [members[random].id], "remove") 35 | mmm-- 36 | kicked++ 37 | } 38 | m._reply(m.lang(msg).success.replace('{kicked}', kicked)) 39 | } else { 40 | let members = m.db.group.member_activity 41 | members = Object.entries(members).filter(v => v[1] == score) 42 | mmm = members.length 43 | for(let i = 0; i < member; i++){ 44 | let random = Math.floor(Math.random() * members.length) 45 | if(mmm == 0) break 46 | await delay(1000) 47 | await sock.groupParticipantsUpdate(m.chat, [members[random][0]], "remove") 48 | mmm-- 49 | kicked++ 50 | } 51 | m._reply(m.lang(msg).success.replace('{kicked}', kicked)) 52 | } 53 | 54 | } catch(error) { 55 | await m._reply(error.message) 56 | } 57 | } 58 | } 59 | 60 | const msg = { 61 | id: { 62 | ex: 'Penggunaan:\n\n{prefix}randomkick `score` `member`\n\n*Keterangan:*\n- *score*: Skor aktivitas anggota.\n- *member*: jumlah anggota yang akan di-kick.', 63 | inactive: 'Group ini tidak mengaktifkan fitur activity record.', 64 | success: 'Berhasilang mengeluarkan {kicked} anggota.' 65 | }, 66 | en: { 67 | ex: 'Usage:\n\n{prefix}random-kick `score` `member`\n\n*Description:*\n- *score*: Member activity score.\n- *member*: Mention the member you want to kick.', 68 | inactive: 'This group does not have activity record feature.', 69 | success: 'Kicked {kicked} members.' 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/command/group/record-activity.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | 3 | module.exports = { 4 | name : "group-activity", 5 | description : "Mengaktifkan dan menonaktifkan Activity record group", 6 | cmd : ['grecord', 'activity'], 7 | menu : { 8 | label : 'group', 9 | example : '' 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.isGroup) return 14 | if(!m.isGroup.senderIsAdmin) return 15 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 16 | 17 | if(m.body.arg == 'enable' || m.body.arg == 'on' || m.body.arg == 'true') { 18 | await db.update(db.group, m.isGroup.groupMetadata.id, { activity_record: true }) 19 | await m._reply(m.lang(msg).active) 20 | } else if(m.body.arg == 'disable' || m.body.arg == 'off' || m.body.arg == 'false') { 21 | await db.update(db.group, m.isGroup.groupMetadata.id, { activity_record: false }) 22 | await m._reply(m.lang(msg).inactive) 23 | } else { 24 | await m._reply(m.lang(msg).ex) 25 | } 26 | } catch(error) { 27 | await m._reply(error.message) 28 | } 29 | } 30 | } 31 | 32 | const msg = { 33 | id: { 34 | ex: 'Penggunaan: {prefix}grecord ``\n\n*Keterangan:*\n- *enable*: Bot akan merecord aktivitas member group.\n- *disable*: Bot tidak akan merecord aktivitas member group.', 35 | active: 'Record aktivitas member group telah diaktifkan.', 36 | inactive: 'Record aktivitas member group telah dinonaktifkan.' 37 | }, 38 | en: { 39 | ex: 'Usage: {prefix}grecord ``\n\n*Keterangan:*\n- *enable*: Bot will record group member activity.\n- *disable*: Bot will not record group member activity.', 40 | active: 'Group member activity recording has been activated.', 41 | inactive: 'Group member activity recording has been deactivated.' 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/command/group/timeout-list.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "group-timeout-list", 6 | description : "Menampilkan member yang timeout di group", 7 | cmd : ['timeout-list', 'tolist', 'bungkam-list'], 8 | menu : { 9 | label : 'group', 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.isGroup) return 14 | if(!m.isGroup.botIsAdmin) return 15 | 16 | const timeouts = db.group.get(m.isGroup.groupMetadata.id).timeouts 17 | 18 | let text = `${m.lang(msg).desc} ${m.isGroup.groupMetadata.subject}\n\n` 19 | for (const [key, value] of Object.entries(timeouts)) { 20 | text += `*${key}*\n` 21 | text += `▷ Date Expired: _${moment(value).format('DD-MM-YYYY HH:mm:ss')}_\n` 22 | text += `▷ Time Left: _${moment(value).diff(moment(), 'minutes')} minutes ${moment(value).diff(moment(), 'seconds') % 60} seconds_\n` 23 | } 24 | 25 | await m._sendMessage(m.chat, { text: text }, { quoted: m }) 26 | } catch(error) { 27 | await m._reply(error.message) 28 | } 29 | } 30 | } 31 | 32 | const msg = { 33 | id: { 34 | desc: 'Menampilkan member yang timeout di', 35 | }, 36 | en: { 37 | desc: 'List of members who have been timed out in', 38 | } 39 | } -------------------------------------------------------------------------------- /src/command/group/timeout.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "group-timeout", 6 | description : "Timeout member nakal", 7 | cmd : ['timeout', 'to', 'bungkam'], 8 | menu : { 9 | label : 'group', 10 | example : ' @mentions' 11 | }, 12 | run : async({ m, sock }) => { 13 | try { 14 | if(!m.isGroup) return 15 | if(!m.isGroup.botIsAdmin) return 16 | if(!m.isGroup.senderIsAdmin) return 17 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 18 | if(!m.mentionedJid.length) return m._reply(m.lang(msg).noMention) 19 | const durationInMinutes = m.body.arg.split(' ')[0] 20 | if(isNaN(durationInMinutes)) return m._reply(m.lang(msg).noDuration) 21 | const timeoutEnd = moment().add(durationInMinutes, 'minutes').valueOf() 22 | const users = {}; 23 | for(mention of m.mentionedJid) { 24 | users[mention] = timeoutEnd 25 | } 26 | 27 | await db.update( 28 | db.group, 29 | m.isGroup.groupMetadata.id, 30 | { 31 | timeouts: { 32 | ...db.group.get(m.isGroup.groupMetadata.id).timeouts || {}, 33 | ...users 34 | } 35 | } 36 | ) 37 | 38 | if(durationInMinutes == 0) return m._reply(`${m.mentionedJid.length} ${m.lang(msg).zero}`) 39 | await m._reply(`${m.mentionedJid.length} ${m.lang(msg).success[0]} ${durationInMinutes} ${m.lang(msg).success[1]}`) 40 | } catch(error) { 41 | await m._reply(error.message) 42 | } 43 | } 44 | } 45 | 46 | const msg = { 47 | id: { 48 | ex: 'Penggunaan: {prefix}timeout `` `@mentions`\n\n*Keterangan:*\n- *durasi*: Waktu yang diberikan kepada member yang di-mention dalam satuan menit.\n- *@mentions*: Sebut anggota yang ingin dikenakan timeout.', 49 | noMention: 'Tidak ada member yang di-mention. Silakan sebut anggota yang ingin dikenakan timeout.', 50 | noDuration: 'Durasi waktu harus berupa angka yang menunjukkan menit.', 51 | success: ['Member telah di timeout selama', 'menit.'], 52 | zero: 'member telah di nyatakan sehat.' 53 | }, 54 | en: { 55 | ex: 'Usage: {prefix}timeout `` `@mentions`\n\n*Description:*\n- *duration*: The time to give to the mentioned members in minutes.\n- *@mentions*: Mention the members you want to apply the timeout to.', 56 | noMention: 'No member mentioned. Please mention the members to apply timeout.', 57 | noDuration: 'Duration must be a number indicating minutes.', 58 | success: ['Members have been timed out for', 'minutes.'], 59 | zero: 'Members have been declared healthy.' 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/command/group/welcome-message.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "group-welcome-message", 6 | description : "Manage Message Group Welcome", 7 | cmd : ['welcomemessage', 'setwelcome-message'], 8 | menu : { 9 | label : 'group', 10 | example : 'text' 11 | }, 12 | run : async({ m, sock }) => { 13 | try { 14 | if(!m.isGroup) return 15 | if(!m.isGroup.botIsAdmin) return 16 | if(!m.isGroup.senderIsAdmin) return 17 | 18 | if(m.body.arg) { 19 | await db.update(db.group, m.isGroup.groupMetadata.id, { welcome_message: m.body.arg, updated_at: moment() }) 20 | await m._reply(m.lang(msg).custom) 21 | } else { 22 | await db.update(db.group, m.isGroup.groupMetadata.id, { welcome_message: null, updated_at: moment() }) 23 | await m._reply(m.lang(msg).default) 24 | } 25 | } catch(error) { 26 | await m._reply(error.message) 27 | } 28 | } 29 | } 30 | 31 | const msg = { 32 | id: { 33 | ex: 'penggunaan: {prefix}welcomemessage `text`\nContoh: {prefix}welcomemessage Selamat datang di group {group.name} {mention}.', 34 | custom: 'Berhasil mengganti pesan grup selamat datang.', 35 | default: 'Pesan grup selamat datang telah diatur ke default.' 36 | }, 37 | en: { 38 | ex: 'usage: {prefix}welcomemessage `text`\nExample: {prefix}welcomemessage Welcome to group {group.name} {mention}.', 39 | custom: 'Successfully changed the group welcome message.', 40 | default: 'Group welcome message has been reset to default.' 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/command/group/welcome.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | 3 | module.exports = { 4 | name : "group-welcome", 5 | description : "Manage Welcome Message Group", 6 | cmd : ['set-welcome'], 7 | menu : { 8 | label : 'group', 9 | example : '' 10 | }, 11 | run : async({ m, sock }) => { 12 | try { 13 | if(!m.isGroup) return 14 | if(!m.isGroup.botIsAdmin) return 15 | if(!m.isGroup.senderIsAdmin) return 16 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 17 | if(m.body.arg == 'enable' || m.body.arg == 'on' || m.body.arg == 'true') { 18 | await db.update(db.group, m.isGroup.groupMetadata.id, { welcome: true }) 19 | await m._reply(m.lang(msg).active) 20 | } else if(m.body.arg == 'disable' || m.body.arg == 'off' || m.body.arg == 'false') { 21 | await db.update(db.group, m.isGroup.groupMetadata.id, { welcome: false }) 22 | await m._reply(m.lang(msg).inactive) 23 | } else { 24 | await m._reply(m.lang(msg).ex) 25 | } 26 | } catch(error) { 27 | await m._reply(error.message) 28 | } 29 | } 30 | } 31 | 32 | const msg = { 33 | id: { 34 | ex: 'Penggunaan: {prefix}set-welcome ``\n\n*Keterangan:*\n- *enable*: Mengaktifkan fitur sambutan di grup ini.\n- *disable*: Menonaktifkan fitur sambutan untuk semua anggota.', 35 | active: 'Fitur sambutan telah diaktifkan di grup ini.', 36 | inactive: 'Fitur sambutan telah dinonaktifkan untuk semua anggota.' 37 | }, 38 | en: { 39 | ex: 'Usage: {prefix}set-welcome ``\n\n*Description:*\n- *enable*: Activates the welcome feature in this group.\n- *disable*: Disables the welcome feature for all members.', 40 | active: 'Welcome feature has been activated in this group.', 41 | inactive: 'Welcome feature has been disabled for all members.' 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/command/info/change-name.js: -------------------------------------------------------------------------------- 1 | const db = require("../../utils/db.js") 2 | const moment = require("../../utils/moment.js") 3 | 4 | module.exports = { 5 | name: "info-change-name", 6 | description: "Change name user", 7 | cmd: ['changename', 'cn', 'cname', 'rename'], 8 | menu: { 9 | label: 'info', 10 | example: 'name' 11 | }, 12 | limit: 5, 13 | run: async ({ m, sock }) => { 14 | const name = m.body.arg.replace(/[^A-Za-z ]/g, ''); 15 | if(!name) return m._reply(m.lang(msg).ex); 16 | if(name.length < 3) return m._reply(m.lang(msg).min); 17 | if(name.length > 15) return m._reply(m.lang(msg).max); 18 | await db.update(db.user, m.sender, { name, limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 19 | await m._reply(m.lang(msg).success); 20 | } 21 | } 22 | 23 | const msg = { 24 | id: { 25 | ex: 'penggunaan: {prefix}cn `nama`', 26 | min: 'Minimal 3 huruf.', 27 | max: 'Maksimal 15 huruf.', 28 | success: 'Nama kamu berhasil di perbarui.' 29 | }, 30 | en: { 31 | ex: 'usage: {prefix}cn `name`', 32 | min: 'Minimal 3 character.', 33 | max: 'Maximal 15 character.', 34 | success: 'Your name has been successfully updated.' 35 | } 36 | } -------------------------------------------------------------------------------- /src/command/info/creator.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "info-creater", 3 | description: "Show Contact Creator", 4 | cmd: ['creator', 'author'], 5 | menu: { 6 | label: 'info' 7 | }, 8 | run: async ({ m, sock }) => { 9 | const [ number, name ] = Object.entries(m.db.bot.owners)[0] 10 | const vcard = 'BEGIN:VCARD\n' // metadata of the contact card 11 | + 'VERSION:3.0\n' 12 | + `FN:${name}\n` // full name 13 | + `ORG:${name};\n` // the organization of the contact 14 | + `TEL;type=CELL;type=VOICE;waid=${number}:+${number}\n` // WhatsApp ID + phone number 15 | + 'END:VCARD' 16 | await sock.sendMessage( 17 | m.chat, 18 | { 19 | contacts: { 20 | displayName: `${name}`, 21 | contacts: [{ vcard }] 22 | } 23 | } 24 | ) 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/command/info/ping.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | const fs = require('fs') 3 | 4 | function toTime(ms) { 5 | let seconds = Math.floor((ms / 1000) % 60) 6 | let minutes = Math.floor((ms / (1000 * 60)) % 60) 7 | let hours = Math.floor((ms / (1000 * 60 * 60)) % 24) 8 | let days = Math.floor(ms / (1000 * 60 * 60 * 24)) 9 | 10 | return `${days}d ${hours}h ${minutes}m ${seconds}s` 11 | } 12 | 13 | function formatSize(bytes) { 14 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'] 15 | if (bytes === 0) return '0 Byte' 16 | const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))) 17 | return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}` 18 | } 19 | 20 | module.exports = { 21 | name: "info-ping", 22 | description: "Ping", 23 | cmd: ['ping', 'p'], 24 | menu: { 25 | label: 'info' 26 | }, 27 | run: async ({ m, sock }) => { 28 | let start = performance.now(); 29 | let text = `*\`❖ Server Info\`*\n`; 30 | text += `▷ Running On : ${process.env.username === 'root' ? "VPS" : "HOSTING ( PANEL )"}\n` 31 | text += `▷ Node Version : ${process.version}\n\n` 32 | text += `*\`❖ Management Server\`*\n` 33 | text += `▷ Speed : ${(performance.now() - start).toFixed(5)} ms\n` 34 | text += `▷ Uptime : ${toTime(process.uptime() * 1000)}\n` 35 | text += `▷ Total Memory : ${formatSize(os.freemem())}/${formatSize(os.totalmem())}\n` 36 | text += `▷ CPU : ${os.cpus()[0].model} ( ${os.cpus().length} CORE )\n` 37 | text += `▷ Release : ${os.release()}\n` 38 | text += `▷ Type : ${os.type()}` 39 | m._reply(text); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/command/info/profile.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js'); 2 | const moment = require('../../utils/moment.js'); 3 | const currency = require('../../utils/currency.js'); 4 | const { BlockchainDB } = require('../../utils/blockchain/index.js'); 5 | const blockchain = new BlockchainDB(); 6 | 7 | module.exports = { 8 | name: "info-user", 9 | description: "Show Profile User", 10 | cmd: ['profile', 'user', 'id'], 11 | menu: { 12 | label: 'info' 13 | }, 14 | withoutMiddleware: ['timeout.js'], 15 | run: async ({ m, sock }) => { 16 | let dbuser = null, 17 | avatar = "https://i.ibb.co.com/1QRWZTd/146de169d3133554a6d907b837d31377.jpg", 18 | timeoutGroup = null, 19 | id = null; 20 | 21 | if(m.quoted) { 22 | id = m.quoted.sender 23 | } else if (m.mentionedJid.length) { 24 | id = m.mentionedJid[0] 25 | } else { 26 | id = m.sender 27 | } 28 | const leaderboard = Object.entries(m.db?.group?.member_activity || {}) 29 | .sort(([, a], [, b]) => b - a) 30 | .slice(0, 10) 31 | .map(([member, activity], index) => ({ 32 | rank: index + 1, 33 | member, 34 | activity 35 | })); 36 | 37 | try { 38 | avatar = await sock.profilePictureUrl(id, 'image') 39 | } catch {} finally { 40 | dbuser = db.user.get(id) 41 | if(!dbuser) return m._reply(m.lang(msg).userNotFound) 42 | 43 | timeoutGroup = Object.keys(m.db?.group?.timeouts || {}).find(x => x == id) 44 | 45 | let caption = `\`❖ PERSONAL\`\n`; 46 | caption += `▷ Name : ${dbuser.name}\n` 47 | if(dbuser.plan != 'free') { 48 | caption += `▷ Plan : ${dbuser.plan.charAt(0).toUpperCase() + m.db.user.plan.slice(1)}\n` 49 | } 50 | if(m.db.user.plan != 'free') caption += `Expired : ${dbuser.plan_expire}\n` 51 | caption += `▷ Exp : ${dbuser.exp}\n` 52 | caption += `▷ Balance \`Blockchain\` : ${currency.format(await blockchain.getBalance(id))}\n` 53 | caption += `▷ Point : ${currency.format(dbuser.balance)}\n` 54 | caption += `▷ Limit : ${dbuser.limit == 'unlimited' ? 'Unlimited' : dbuser.limit}\n\n` 55 | if(m.isGroup) { 56 | caption += `\`❖ GROUP ID\`\n` 57 | caption += `▷ Timeout Group : ${timeoutGroup ? `${moment(m.db.group.timeouts[timeoutGroup]).diff(moment(), 'minutes')} minutes ${moment(m.db.group.timeouts[timeoutGroup]).diff(moment(), 'seconds') % 60} seconds` : '-'}\n` 58 | caption += `▷ Leaderboard : ${leaderboard.find(({member}) => member == id)?.rank || '-'} of ${m.isGroup.groupMetadata.size}\n` 59 | caption += `\n\n` 60 | } 61 | caption += `▷ Blacklist : ${dbuser.blacklist_reason || '-'}\n` 62 | caption += `▷ Last Online : ${moment(dbuser.updated_at).fromNow()}\n` 63 | caption += `▷ Registered : ${moment(dbuser.created_at).fromNow()}\n\n` 64 | caption += `> For more information blockchain balance and history transaction type \`${m.body.prefix}getbalance\`` 65 | 66 | await m._sendMessage(m.chat, { 67 | text : caption, 68 | contextInfo: { 69 | externalAdReply: { 70 | title: dbuser.name, 71 | body: id, 72 | mediaType: 2, 73 | thumbnailUrl: avatar, 74 | sourceUrl: 'https://velixs.com', 75 | } 76 | } 77 | }, { quoted: m }); 78 | } 79 | } 80 | } 81 | 82 | const msg = { 83 | id: { 84 | userNotFound: 'User tidak terdaftar.', 85 | }, 86 | en: { 87 | userNotFound: 'User not found.', 88 | } 89 | } -------------------------------------------------------------------------------- /src/command/internet/gempa.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | 3 | module.exports = { 4 | name: "internet-gempa", 5 | description: "Menampilkan informasi gempa dari bmkg", 6 | cmd: ['gempa'], 7 | menu: { 8 | label: 'internet' 9 | }, 10 | run: async ({ m, sock }) => { 11 | m._react(m.key, '🔍') 12 | const res = await axios.get("https://data.bmkg.go.id/DataMKG/TEWS/autogempa.json") 13 | const gempa = res.data.Infogempa.gempa; 14 | let caption = `*${gempa.Wilayah}*\n\n` 15 | caption += `Tanggal : ${gempa.Tanggal}\n` 16 | caption += `Waktu : ${gempa.Jam}\n` 17 | caption += `Potensi : *${gempa.Potensi}*\n\n` 18 | caption += `Magnitude : ${gempa.Magnitude}\n` 19 | caption += `Kedalaman : ${gempa.Kedalaman}\n` 20 | caption += `Koordinat : ${gempa.Coordinates}${gempa.Dirasakan.length > 3 ? `\nDirasakan : ${gempa.Dirasakan}` : ''}` 21 | await m._sendMessage(m.chat, { image : { url : "https://data.bmkg.go.id/DataMKG/TEWS/"+gempa.Shakemap }, caption }, { quoted: m }) 22 | m._react(m.key, '✅') 23 | } 24 | } -------------------------------------------------------------------------------- /src/command/internet/lyric.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios") 2 | const db = require("../../utils/db.js") 3 | 4 | module.exports = { 5 | name: "internet-lyric", 6 | description: "Mencari Lyric Music", 7 | cmd: ['lyric', 'lyrics'], 8 | menu: { 9 | label: 'internet' 10 | }, 11 | limit: 1, 12 | run: async ({ m, sock }) => { 13 | m._react(m.key, '🔍') 14 | const res = await axios.get("https://api.nyxs.pw/tools/lirik?title="+m.body.arg) 15 | await m._reply(res.data.result) 16 | m._react(m.key, '✅') 17 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 18 | } 19 | } -------------------------------------------------------------------------------- /src/command/internet/ssweb.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios"); 2 | const db = require("../../utils/db.js"); 3 | 4 | module.exports = { 5 | name : "ssweb", 6 | description : "Screenshot Website", 7 | cmd : ['ssweb'], 8 | menu : { 9 | label : 'internet', 10 | example : 'url' 11 | }, 12 | limit : 1, 13 | run : async({ m, sock }) => { 14 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 15 | let res = null 16 | m._react(m.key, '🔍') 17 | try { 18 | try { 19 | res = await axios.get(`https://api.screenshotmachine.com/?key=f74eca&url=${m.body.arg}&dimension=1920x1080`, { responseType: 'arraybuffer' }) 20 | } catch { 21 | try { 22 | res = await axios.get(`https://image.thum.io/get/fullpage/${m.body.arg}`, { responseType: 'arraybuffer' }) 23 | } catch { 24 | res = await axios.get(`https://api.screenshotmachine.com/?key=c04d3a&url=${m.body.arg}&screenshotmachine.com&dimension=720x720`, { responseType: 'arraybuffer' }) 25 | } 26 | } 27 | await m._sendMessage(m.chat, { image : res.data }, { quoted : m }) 28 | m._react(m.key, '✅') 29 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) - parseInt(m.commandLimit)) }); 30 | } catch (error) { 31 | m._react(m.key, '❌') 32 | await m._reply(error.message) 33 | } 34 | } 35 | } 36 | 37 | const msg = { 38 | id: { 39 | ex: 'Penggunaan: {prefix}ssweb ``\n\n*Keterangan:*\n- **: URL situs web yang ingin Anda ambil tangkapan layarnya.', 40 | }, 41 | en: { 42 | ex: 'Usage: {prefix}ssweb ``\n\n*Description:*\n- **: The URL of the website you want to capture a screenshot of.', 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/command/menu-owner.js: -------------------------------------------------------------------------------- 1 | const timer2 = require("../utils/timer2.js") 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const config = require("../../config.js"); 5 | 6 | module.exports = { 7 | name : "menu-owner", 8 | description : "Menu Owner Bot", 9 | cmd : ['mowner', 'menu-owner'], 10 | run : async({ m, sock }) => { 11 | if(!m.senderIsOwner) return 12 | let text = '' 13 | text += `*😺 Menu* ඞ\n ${timer2()} \n\n` 14 | text += `┌── ˗ˏˋ ★ Owner Menu ★ ˎˊ˗\n` 15 | text += `▷ ${m.body.prefix}bot \n` 16 | text += `▷ ${m.body.prefix}clear \n` 17 | text += `▷ ${m.body.prefix}block \n` 18 | text += `▷ ${m.body.prefix}unblock \n` 19 | text += `▷ ${m.body.prefix}iconmsg \n` 20 | text += `▷ ${m.body.prefix}setpp \n` 21 | text += `▷ ${m.body.prefix}join \n` 22 | text += `▷ ${m.body.prefix}leave \n` 23 | text += `▷ ${m.body.prefix}mode \n` 24 | text += `▷ ${m.body.prefix}lang \n` 25 | text += `▷ ${m.body.prefix}prefix\n` 26 | text += `▷ ${m.body.prefix}owner\n` 27 | text += `▷ ${m.body.prefix}groups\n` 28 | text += `▷ ${m.body.prefix}owner\n` 29 | text += `▷ ${m.body.prefix}exif\n` 30 | text += `▷ ${m.body.prefix}unreg \`@mention\`\n` 31 | text += `▷ ${m.body.prefix}addbalance \`nominal\` \`@mentions\`\n` 32 | text += `▷ ${m.body.prefix}setbalance \`nominal\` \`@mentions\`\n` 33 | text += `▷ ${m.body.prefix}$\n` 34 | text += `▷ ${m.body.prefix}~\n` 35 | text += `└────────────\n\n` 36 | 37 | text += `\n` 38 | text += `_👑 author: Ilsya_\n` 39 | await m._sendMessage(m.chat, { 40 | text, 41 | contextInfo: { 42 | externalAdReply: { 43 | title: 'Nakiri Whatsapp BOT', 44 | body: '- Menu -', 45 | mediaType: 2, 46 | thumbnail: m.db.bot.icon, 47 | sourceUrl: 'https://velixs.com', 48 | } 49 | } 50 | }, { quoted: m }); 51 | } 52 | } -------------------------------------------------------------------------------- /src/command/menu.js: -------------------------------------------------------------------------------- 1 | const { menuByLabel } = require("../utils/loadCommands.js") 2 | const timer2 = require("../utils/timer2.js") 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const config = require("../../config.js"); 6 | 7 | module.exports = { 8 | name : "menu", 9 | description : "Menu Bot Velixs-Bot", 10 | cmd : ['help', 'menu'], 11 | run : async({ m, sock }) => { 12 | let text = '' 13 | let label = 'All Menu'; 14 | text += `*\`Hai ${m.db.user.name}\`*\nSelamat ${timer2()} \n\n` 15 | text += `\`Blockchain\`\n> Mata uang bot yang bisa kamu gunakan untuk membeli limit taruhan dan lain lain.\n\n\n` 16 | text += String.fromCharCode(8206).repeat(4001) 17 | if(m.body.arg) { 18 | let filterMenu = menuByLabel.get(m.body.arg) 19 | if(!filterMenu) return 20 | label = m.body.arg.toUpperCase() 21 | text += `\`❖ ${m.body.arg.toUpperCase()}\`\n` 22 | filterMenu.forEach((v) => { 23 | text += `▷ ${m.body.prefix + v.cmd[0]} ${v?.example ? '_' + v.example + '_' : ''}\n` 24 | }) 25 | } else { 26 | menuByLabel.forEach((val, key) => { 27 | text += `\`❖ ${key.toUpperCase()}\`\n` 28 | val.forEach((v) => { 29 | text += `▷ ${m.body.prefix + v.cmd[0]} ${v?.example ? '_' + v.example + '_' : ''}\n` 30 | }) 31 | text += `\n` 32 | }) 33 | } 34 | text += `\n` 35 | text += `_👑 author: Ilsya_\n` 36 | 37 | await m._sendMessage(m.chat, { 38 | text, 39 | contextInfo: { 40 | externalAdReply: { 41 | title: 'Nakiri Whatsapp BOT', 42 | body: `- ${label} -`, 43 | mediaType: 2, 44 | thumbnail: m.db.bot.icon, 45 | sourceUrl: 'https://velixs.com', 46 | } 47 | } 48 | }, { quoted: m }); 49 | } 50 | } -------------------------------------------------------------------------------- /src/command/owner/add-balance.js: -------------------------------------------------------------------------------- 1 | const currency = require('../../utils/currency.js') 2 | const moment = require('../../utils/moment.js') 3 | const db = require('../../utils/db.js') 4 | 5 | module.exports = { 6 | name: "owner-add-coin", 7 | description: "Add Balance", 8 | cmd: ['addbalance', 'addcoin', 'addsaldo'], 9 | run: async ({ m, sock }) => { 10 | if(!m.senderIsOwner) return 11 | 12 | let ids = [], balance, nameText = 0, balanceText; 13 | 14 | if(m.quoted) { 15 | ids = [ m.quoted.sender ] 16 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 17 | } else if(m.mentionedJid.length) { 18 | ids = m.mentionedJid 19 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 20 | } else if(m.body.arg.split(' ')[1] == 'all') { 21 | for(let user of db.user.getRange()) { 22 | ids = ids.concat(user.key) 23 | } 24 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 25 | } else if (m.body.arg.split(' ')[1]) { 26 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 27 | ids = [ m.body.arg.split(' ')[1].replace(/[^0-9]/g, '')+'@s.whatsapp.net' ] 28 | } else return m._reply(m.lang(msg).ex) 29 | 30 | for(const id of ids) { 31 | const user = await db.user.get(id); 32 | if(!user && ids.length == 1) return m._reply(m.lang(msg).userNotFound); 33 | if(!user && ids.length > 1) continue; 34 | await db.update(db.user, id, { balance: currency.add(user.balance, balance) , updated_at: moment() }); 35 | balanceText = currency.format(balance) 36 | if(ids.length == 1) { 37 | nameText = user.name 38 | } else { 39 | nameText = parseInt(nameText)+1 40 | } 41 | } 42 | if (ids.length > 1) nameText = nameText + ' ' + m.lang(msg).users; 43 | await m._reply(m.lang(msg).success.replace('{name}', nameText ).replace('{balance}', currency.format(balanceText))); 44 | 45 | } 46 | } 47 | 48 | const msg = { 49 | id: { 50 | userNotFound: 'Pengguna tidak terdaftar.', 51 | success: 'Saldo `{name}` ditambahkan sebesar `{balance}`.', 52 | ex: 'Penggunaan:\n▷ {prefix}addbalance `nominal` `<@mentions|all>`\n▷ Balas pesan dengan caption {prefix}addcoin `nominal`', 53 | users: 'pengguna', 54 | }, 55 | en: { 56 | userNotFound: 'User not found.', 57 | success: 'Balance `{name}` has been added with `{balance}`.', 58 | ex: 'Usage:\n▷ {prefix}addbalance `nominal` `<@mentions|all>`\n▷ Reply to a message with caption {prefix}addcoin `nominal`', 59 | users: 'users' 60 | } 61 | } -------------------------------------------------------------------------------- /src/command/owner/block.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "block", 3 | description: "Blockir Number", 4 | cmd: ['block'], 5 | run: async ({ m, sock }) => { 6 | if(!m.senderIsOwner) return 7 | if(!m.mentionedJid.length && !m.quoted) return m._reply(m.lang(msg).ex) 8 | 9 | try { 10 | if(m.quoted) await sock.updateBlockStatus(m.quoted.sender, "block") 11 | for (let i of m?.mentionedJid || []) { 12 | await sock.updateBlockStatus(i, "block") 13 | } 14 | m._reply(`${m.mentionedJid.length} ${m.lang(msg).success}`) 15 | } catch(error) { 16 | await m._reply(error.message) 17 | } 18 | } 19 | } 20 | 21 | const msg = { 22 | id: { 23 | ex: 'Sebut (mention) atau balas pesan badut yang ingin diblokir.', 24 | success: 'Badut telah berhasil diblokir.' 25 | }, 26 | en: { 27 | ex: 'Mention or reply to the bad guy you want to block.', 28 | success: 'Bad guy has been successfully blocked.' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/command/owner/bot-info.js: -------------------------------------------------------------------------------- 1 | const db = require("../../utils/db.js") 2 | const util = require('util') 3 | 4 | module.exports = { 5 | name : "bot-info", 6 | description : "Show Bot Info", 7 | cmd : ['bot', 'botinfo'], 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.senderIsOwner) return 11 | let text = `*Bot Status*\n\n` 12 | text += `*Group*: ${db.group.getCount()} Total\n*` 13 | text += `User*: ${db.user.getCount()} Registered\n\n*` 14 | text += String.fromCharCode(8206).repeat(4001) 15 | text += `Bot Settings*\n` 16 | text += util.format(m.db.bot) 17 | m._reply(text) 18 | } catch(error) { 19 | await m._reply(error.message) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/command/owner/clear.js: -------------------------------------------------------------------------------- 1 | const config = require("../../../config.js") 2 | const db = require("../../utils/db.js") 3 | const path = require("path") 4 | const fs = require("fs") 5 | 6 | module.exports = { 7 | name : "bot-clear", 8 | description : "Clear Cache Bot", 9 | cmd : ['clear', 'refresh'], 10 | run : async({ m, sock }) => { 11 | try { 12 | if(!m.senderIsOwner) return 13 | 14 | const groupExists = await sock.groupFetchAllParticipating() 15 | let deletedGroups = 0 16 | for (let { key, value } of db.group.getRange()) { 17 | if(groupExists[key]) continue 18 | await db.group.remove(key) 19 | deletedGroups++ 20 | } 21 | 22 | const dirTemp = path.join(config.STORAGE_PATH, 'temp') 23 | let files = fs.readdirSync(dirTemp) 24 | let deletedFiles = 0 25 | for (let file of files) { 26 | if(file === '.gitignore') continue 27 | fs.unlinkSync(path.join(dirTemp, file)) 28 | deletedFiles++ 29 | } 30 | 31 | let text = `*\`❖ Clear Cache\`*\n\n` 32 | text += `▷ Total Group: ${db.group.getCount()}\n` 33 | text += `▷ Deleted Group: ${deletedGroups}\n\n` 34 | text += `▷ Temp Files: ${files.length}\n` 35 | text += `▷ Deleted Temp Files: ${deletedFiles}\n\n` 36 | 37 | await m._sendMessage(m.chat, { 38 | text, 39 | contextInfo: { 40 | externalAdReply: { 41 | title: 'Nakiri Whatsapp BOT', 42 | body: '- Clear Cache -', 43 | mediaType: 2, 44 | thumbnail: m.db.bot.icon, 45 | sourceUrl: 'https://velixs.com', 46 | } 47 | } 48 | }, { quoted: m }); 49 | } catch(error) { 50 | await m._reply(error.message) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/command/owner/exc.js: -------------------------------------------------------------------------------- 1 | const util = require("util"); 2 | const { 3 | exec 4 | } = require("child_process"); 5 | const axios = require("axios"); 6 | const db = require("../../utils/db.js"); 7 | const moment = require("../../utils/moment.js"); 8 | const fs = require("fs"); 9 | const cheerio = require("cheerio"); 10 | 11 | module.exports = { 12 | name: "exc", 13 | description: "Command Owner", 14 | cmd: ['~', '$'], 15 | withoutPrefix: true, 16 | run: async ({ m, sock }) => { 17 | if(!m.senderIsOwner) return 18 | if(!m.body.arg) return 19 | 20 | if (m.body.full.startsWith('~')) { 21 | try { 22 | const result = await eval(`(async() => { ${m.body.full.slice(2)} })()`); 23 | m._reply(util.format(result)); 24 | } catch (e) { 25 | m._reply(util.format(e)) 26 | } 27 | } 28 | 29 | if (m.body.full.startsWith('$')) { 30 | let { 31 | key 32 | } = await m._sendMessage( 33 | m.chat, { 34 | text: "executed...", 35 | }, { 36 | quoted: m, 37 | }, 38 | ); 39 | exec(m.body.full.slice(2), async (err, stdout) => { 40 | if (err) 41 | return await m._sendMessage(m.chat, { 42 | text: util.format(err), 43 | edit: key, 44 | }); 45 | if (stdout) 46 | return await m._sendMessage(m.chat, { 47 | text: stdout, 48 | edit: key, 49 | }); 50 | }); 51 | } 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /src/command/owner/exif.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "bot-exif", 6 | description : "Set Bot Exif", 7 | cmd : ['exif'], 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.senderIsOwner) return 11 | 12 | let [pack, author] = m.body.arg.trim().split('|') 13 | if(!pack && !author) return m._reply(m.lang(msg).ex) 14 | db.update(db.bot, 'settings', { exif: { pack, author }, updated_at: moment() }) 15 | await m._reply(m.lang(msg).success) 16 | } catch(error) { 17 | await m._reply(error.message) 18 | } 19 | } 20 | } 21 | 22 | const msg = { 23 | id: { 24 | ex: 'Penggunaan: {prefix}exif ``\n\n**Keterangan:**\n- **``**: Nama paket yang akan digunakan untuk exif.\n- **``**: Nama penulis yang akan digunakan untuk exif.', 25 | success: 'Exif telah berhasil diatur.' 26 | }, 27 | en: { 28 | ex: 'Usage: {prefix}exif ``\n\n**Description:**\n- **``**: The pack name to be used for exif.\n- **``**: The author name to be used for exif.', 29 | success: 'Exif has been successfully set.' 30 | } 31 | } -------------------------------------------------------------------------------- /src/command/owner/get-group.js: -------------------------------------------------------------------------------- 1 | const db = require("../../utils/db.js") 2 | 3 | module.exports = { 4 | name : "owner-get-group", 5 | description : "Show All Group", 6 | cmd : ['getgroup', 'ggroup', 'groups'], 7 | run : async({ m, sock }) => { 8 | try { 9 | if(!m.senderIsOwner) return 10 | let text = `*\`❖ All Group\`*\n\n` 11 | let groups = await sock.groupFetchAllParticipating() 12 | for (let group of Object.values(groups)) { 13 | text += `▷ *${group.id}* - ${group.subject}\n` 14 | } 15 | m._reply(text) 16 | } catch(error) { 17 | await m._reply(error.message) 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/command/owner/icon.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name: "icon-message", 6 | description: "Custom Icon Message", 7 | cmd: ['iconmsg'], 8 | run: async ({ m, sock }) => { 9 | if(!m.senderIsOwner) return 10 | if(!['imageMessage'].includes(m.quoted ? m.quoted.mtype : m.mtype)) return m._reply(m.lang(msg).ex) 11 | const { buffer } = m.quoted ? await m.quoted.download() : await m.download() 12 | await db.update(db.bot, 'settings', { icon: buffer, updated_at: moment() }) 13 | await m._sendMessage(m.chat, { 14 | text: m.lang(msg).success, 15 | contextInfo: { 16 | externalAdReply: { 17 | title: 'Nakiri Whatsapp BOT', 18 | body: '- Success -', 19 | mediaType: 2, 20 | thumbnail: buffer, 21 | sourceUrl: 'https://velixs.com', 22 | } 23 | } 24 | }, { quoted: m }); 25 | } 26 | } 27 | 28 | const msg = { 29 | id: { 30 | ex: 'Balas gambar atau kirim gambar dengan caption `{prefix}iconmsg`.', 31 | success: 'Icon berhasil diubah.' 32 | }, 33 | en: { 34 | ex: 'Reply to an image or send an image with the caption `{prefix}iconmsg`.', 35 | success: 'Icon has been successfully changed.' 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/command/owner/join.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "join", 3 | description: "Join group by link", 4 | cmd: ['join'], 5 | run: async ({ m, sock }) => { 6 | if(!m.senderIsOwner) return 7 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 8 | try { 9 | const codelink = m.body.arg.replace('https://chat.whatsapp.com/', '') 10 | const info = await sock.groupGetInviteInfo(codelink) 11 | await sock.groupAcceptInvite(codelink) 12 | await m._reply(`${m.lang(msg).success} ${info.subject}!`) 13 | } catch(error) { 14 | console.log(error); 15 | await m._reply(m.lang(msg).error) 16 | } 17 | } 18 | } 19 | 20 | const msg = { 21 | id: { 22 | ex: 'Cara penggunaan: {prefix}join ``\n\n*Keterangan:*\n- **: Tautan undangan grup yang ingin Anda masuki.', 23 | success: 'Berhasil masuk ke grup', 24 | error: 'Link grup tidak valid!' 25 | }, 26 | en: { 27 | ex: 'Usage: {prefix}join ``\n\n*Description:*\n- **: The invitation link of the group you want to join.', 28 | success: 'Successfully joined the group', 29 | error: 'Invalid group link!' 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/command/owner/lang.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "bot-lang", 6 | description : "Set Bot Language", 7 | cmd : ['lang'], 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.senderIsOwner) return 11 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 12 | 13 | if(!['id', 'en'].includes(m.body.arg)) return m._reply(m.lang(msg).ex) 14 | await db.update(db.bot, 'settings', { lang: m.body.arg.trim(), updated_at: moment() }) 15 | await m._reply(m.lang(msg).success) 16 | } catch(error) { 17 | await m._reply(error.message) 18 | } 19 | } 20 | } 21 | 22 | const msg = { 23 | id: { 24 | ex: 'Penggunaan: {prefix}lang ``\n\n*Keterangan:*\n- *id*: Mengatur bahasa ke Bahasa Indonesia.\n- *en*: Mengatur bahasa ke Bahasa Inggris.', 25 | success: 'Bahasa berhasil diatur.', 26 | }, 27 | en: { 28 | ex: 'Usage: {prefix}lang ``\n\n*Description:*\n- *id*: Set the language to Indonesian.\n- *en*: Set the language to English.', 29 | success: 'Language has been successfully set.', 30 | } 31 | } -------------------------------------------------------------------------------- /src/command/owner/leave.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "leave", 3 | description: "Leave bot from Group", 4 | cmd: ['leave'], 5 | run: async ({ m, sock }) => { 6 | if(!m.senderIsOwner) return 7 | try { 8 | m._sendMessage(m.chat, { text: 'bye.' }) 9 | setTimeout(async() => { 10 | await sock.groupLeave(m.chat) 11 | }, 1000); 12 | } catch(error) { 13 | await m._reply(error.message) 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/command/owner/mode.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | 3 | module.exports = { 4 | name: "mode-bot", 5 | description: "Fitur mengganti mode bot dari public ke private dan sebaliknya", 6 | cmd: ['mode'], 7 | run: async ({ m, sock }) => { 8 | if(!m.senderIsOwner) return 9 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 10 | 11 | if(m.body.arg == 'public' || m.body.arg == 'pb') { 12 | await db.bot.put('settings', { mode: 'public' }) 13 | await m._reply(m.lang(msg).public) 14 | } else if(m.body.arg == 'private' || m.body.arg == 'pv') { 15 | await db.bot.put('settings', { mode: 'private' }) 16 | await m._reply(m.lang(msg).private) 17 | } else { 18 | await m._reply(m.lang(msg).ex) 19 | } 20 | } 21 | } 22 | 23 | const msg = { 24 | id: { 25 | ex: 'Penggunaan: {prefix}mode ``\n\n*Keterangan:*\n- *public*: Mengatur bot dalam mode publik.\n- *private*: Mengatur bot dalam mode pribadi.', 26 | public: 'Bot telah diatur ke mode publik.', 27 | private: 'Bot telah diatur ke mode pribadi.' 28 | }, 29 | en: { 30 | ex: 'Usage: {prefix}mode ``\n\n*Description:*\n- *public*: Sets the bot to public mode.\n- *private*: Sets the bot to private mode.', 31 | public: 'Bot has been set to public mode.', 32 | private: 'Bot has been set to private mode.' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/command/owner/owners.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "bot-owner", 6 | description : "Set Bot Owner", 7 | cmd : ['owner'], 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.senderIsOwner) return 11 | 12 | // -set -remove 13 | let currentOwner = m.db.bot.owners 14 | let arg = m.body.arg.trim(); 15 | const ActSet = arg.startsWith('-set'); 16 | const ActRemove = arg.startsWith('-remove'); 17 | if(!ActSet && !ActRemove) return m._reply(m.lang(msg).ex) 18 | let setOwner = arg.replace('-set', '').replace('-remove', '').trim(); 19 | if(!setOwner) return m._reply(m.lang(msg).ex) 20 | const [ number, name ] = setOwner.split('|') 21 | if(!number && !name) return m._reply(m.lang(msg).ex) 22 | let hashOwner = Object.keys(currentOwner).find(x => x == number) 23 | 24 | if (ActSet) { 25 | if(hashOwner) return m._reply(m.lang(msg).same) 26 | setOwner = { [number]: name } 27 | currentOwner = { ...currentOwner, ...setOwner } 28 | db.update(db.bot, 'settings', { owners: currentOwner, updated_at: moment() }) 29 | await m._reply(m.lang(msg).success_set) 30 | } else if (ActRemove) { 31 | if(!hashOwner) return m._reply(m.lang(msg).notFound) 32 | delete currentOwner[hashOwner] 33 | db.update(db.bot, 'settings', { owners: currentOwner, updated_at: moment() }) 34 | await m._reply(m.lang(msg).success_remove) 35 | } 36 | } catch(error) { 37 | await m._reply(error.message) 38 | } 39 | } 40 | } 41 | 42 | const msg = { 43 | id: { 44 | ex: 'Penggunaan: {prefix}owner `-set ` atau `-remove`\n\n*Keterangan:*\n- *-set *: Mengatur owner baru. Gunakan nomor dengan kode negara, misalnya 62 untuk Indonesia, dan nama.\n- *-remove *: Menghapus owner yang ada.', 45 | same: 'Nomor tersebut sudah menjadi owner sebelumnya.', 46 | notFound: 'Nomor tidak ditemukan.', 47 | success_set: 'Owner telah berhasil ditambahkan.', 48 | success_remove: 'Owner telah berhasil dihapus.' 49 | }, 50 | en: { 51 | ex: 'Usage: {prefix}owner `-set ` or `-remove`\n\n*Description:*\n- *-set *: Set a new owner. Use a number with country code, e.g., 62 for Indonesia, and name.\n- *-remove *: Remove the existing owner.', 52 | same: 'The number is already an owner.', 53 | notFound: 'Number not found.', 54 | success_set: 'Owner has been successfully added.', 55 | success_remove: 'Owner has been successfully removed.' 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/command/owner/prefix.js: -------------------------------------------------------------------------------- 1 | const db = require('../../utils/db.js') 2 | const moment = require('../../utils/moment.js') 3 | 4 | module.exports = { 5 | name : "bot-prefix", 6 | description : "Set Bot Prefix", 7 | cmd : ['prefix'], 8 | run : async({ m, sock }) => { 9 | try { 10 | if(!m.senderIsOwner) return 11 | 12 | // -set -remove 13 | let currentPrefix = m.db.bot.prefix 14 | let arg = m.body.arg.trim(); 15 | const ActSet = arg.startsWith('-set'); 16 | const ActRemove = arg.startsWith('-remove'); 17 | if(!ActSet && !ActRemove) return m._reply(m.lang(msg).ex) 18 | let setPrefix = arg.replace('-set', '').replace('-remove', '').trim(); 19 | if(!setPrefix) return m._reply(m.lang(msg).ex) 20 | if(setPrefix.length > 1) return m._reply(m.lang(msg).onechar) 21 | 22 | if (ActSet) { 23 | if(currentPrefix.includes(setPrefix)) return m._reply(m.lang(msg).same) 24 | currentPrefix.push(setPrefix) 25 | db.update(db.bot, 'settings', { prefix: currentPrefix, updated_at: moment() }) 26 | await m._reply(m.lang(msg).success_set) 27 | } else if (ActRemove) { 28 | if(!currentPrefix.includes(setPrefix)) return m._reply(m.lang(msg).notFound) 29 | currentPrefix = currentPrefix.filter(x => x !== setPrefix) 30 | db.update(db.bot, 'settings', { prefix: currentPrefix, updated_at: moment() }) 31 | await m._reply(m.lang(msg).success_remove) 32 | } 33 | } catch(error) { 34 | await m._reply(error.message) 35 | } 36 | } 37 | } 38 | 39 | const msg = { 40 | id: { 41 | ex: 'Penggunaan: {prefix}prefix `-set ` atau `-remove`\n\n*Keterangan:*\n- *`-set `*: Mengatur prefix baru.\n- *`-remove`*: Menghapus prefix yang ada.', 42 | onechar: 'Prefix hanya boleh 1 karakter.', 43 | same: 'Prefix sudah ada sebelumnya.', 44 | notFound: 'Prefix tidak ditemukan.', 45 | success_set: 'Prefix telah berhasil diatur.', 46 | success_remove: 'Prefix telah berhasil dihapus.' 47 | }, 48 | en: { 49 | ex: 'Usage: {prefix}prefix `-set ` or `-remove`\n\n*Description:*\n- *`-set `*: Sets a new prefix.\n- *`-remove`*: Removes the existing prefix.', 50 | onechar: 'Prefix must be 1 character only.', 51 | same: 'Prefix already exists.', 52 | notFound: 'Prefix not found.', 53 | success_set: 'Prefix has been successfully set.', 54 | success_remove: 'Prefix has been successfully removed.' 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/command/owner/set-balance.js: -------------------------------------------------------------------------------- 1 | const currency = require('../../utils/currency.js') 2 | const moment = require('../../utils/moment.js') 3 | const db = require('../../utils/db.js') 4 | 5 | module.exports = { 6 | name: "owner-set-coin", 7 | description: "Set Balance", 8 | cmd: ['setbalance', 'setcoin', 'setbalance'], 9 | run: async ({ m, sock }) => { 10 | if(!m.senderIsOwner) return 11 | 12 | let ids = [], balance, nameText = 0, balanceText; 13 | 14 | if(m.quoted) { 15 | ids = [ m.quoted.sender ] 16 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 17 | } else if(m.mentionedJid.length) { 18 | ids = m.mentionedJid 19 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 20 | } else if(m.body.arg.split(' ')[1] == 'all') { 21 | for(let user of db.user.getRange()) { 22 | ids = ids.concat(user.key) 23 | } 24 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 25 | } else if (m.body.arg.split(' ')[1]) { 26 | balance = m.body.arg.split(' ')[0].replace(/[^0-9]/g, '') 27 | ids = [ m.body.arg.split(' ')[1].replace(/[^0-9]/g, '')+'@s.whatsapp.net' ] 28 | } else return m._reply(m.lang(msg).ex) 29 | 30 | for(const id of ids) { 31 | const user = await db.user.get(id); 32 | if(!user && ids.length == 1) return m._reply(m.lang(msg).userNotFound); 33 | if(!user && ids.length > 1) continue; 34 | await db.update(db.user, id, { balance: balance , updated_at: moment() }); 35 | balanceText = currency.format(balance) 36 | if(ids.length == 1) { 37 | nameText = user.name 38 | } else { 39 | nameText = parseInt(nameText)+1 40 | } 41 | } 42 | if (ids.length > 1) nameText = nameText + ' ' + m.lang(msg).users; 43 | await m._reply(m.lang(msg).success.replace('{name}', nameText).replace('{balance}', currency.format(balanceText))); 44 | } 45 | } 46 | 47 | const msg = { 48 | id: { 49 | userNotFound: 'Pengguna tidak terdaftar.', 50 | success: 'Saldo `{name}` di set ke `{balance}`.', 51 | ex: 'Penggunaan:\n▷ {prefix}setbalance `nominal` `<@mentions|all>`\n▷ Balas pesan dengan caption {prefix}setbalance `nominal`', 52 | users: 'pengguna', 53 | }, 54 | en: { 55 | userNotFound: 'User not found.', 56 | success: 'Balance `{name}` has been set to `{balance}`.', 57 | ex: 'Usage:\n▷ {prefix}setbalance `nominal` `<@mentions|all>`\n▷ Reply to a message with caption {prefix}setbalance `nominal`', 58 | users: 'users' 59 | } 60 | } -------------------------------------------------------------------------------- /src/command/owner/setpp.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios') 2 | const { 3 | S_WHATSAPP_NET 4 | } = require('@whiskeysockets/baileys') 5 | const jimp_1 = require('jimp') 6 | 7 | module.exports = { 8 | name: "setpp", 9 | description: "Set Profile Bot", 10 | cmd: ['setpp'], 11 | run: async ({ m, sock }) => { 12 | if(!m.senderIsOwner) return 13 | if(!m.body.arg && !['imageMessage'].includes(m.quoted?.mtype || m.mtype)) return m._reply(m.lang(msg).ex) 14 | 15 | try { 16 | let media; 17 | if (m.body.arg) { 18 | let { data } = await axios.get(m.body.arg, { responseType: 'arraybuffer' }) 19 | media = data 20 | } 21 | if (m.quoted) { 22 | let { buffer } = await m.quoted.download() 23 | media = buffer 24 | } 25 | if (!media) { 26 | let { buffer } = await m.download() 27 | media = buffer 28 | } 29 | 30 | let { img } = await pepe(media) 31 | 32 | await sock.query({ 33 | tag: 'iq', 34 | attrs: { 35 | to: S_WHATSAPP_NET, 36 | type: 'set', 37 | xmlns: 'w:profile:picture' 38 | }, 39 | content: [ 40 | { 41 | tag: 'picture', 42 | attrs: { type: 'image' }, 43 | content: img 44 | } 45 | ] 46 | }) 47 | 48 | m._reply(m.lang(msg).success) 49 | } catch(error) { 50 | await m._reply(error.message) 51 | } 52 | } 53 | } 54 | 55 | async function pepe(media) { 56 | const jimp = await jimp_1.read(media) 57 | const min = jimp.getWidth() 58 | const max = jimp.getHeight() 59 | const cropped = jimp.crop(0, 0, min, max) 60 | return { 61 | img: await cropped.scaleToFit(720, 720).getBufferAsync(jimp_1.MIME_JPEG), 62 | preview: await cropped.normalize().getBufferAsync(jimp_1.MIME_JPEG) 63 | } 64 | } 65 | 66 | const msg = { 67 | id: { 68 | ex: 'Balas atau kirim url gambar untuk di jadikan profile.', 69 | success: 'Profile telah berhasil diubah.' 70 | }, 71 | en: { 72 | ex: 'Reply to an image or send an image with the caption `{prefix}setpp`.', 73 | success: 'Profile has been successfully changed.' 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/command/owner/unblock.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "unblock", 3 | description: "UnBlockir Number", 4 | cmd: ['unblock'], 5 | run: async ({ m, sock }) => { 6 | if(!m.senderIsOwner) return 7 | if(!m.mentionedJid.length && !m.quoted) return m._reply(m.lang(msg).ex) 8 | 9 | try { 10 | if(m.quoted) await sock.updateBlockStatus(m.quoted.sender, "unblock") 11 | for (let i of m?.mentionedJid || []) { 12 | await sock.updateBlockStatus(i, "unblock") 13 | } 14 | m._reply(`${m.mentionedJid.length} ${m.lang(msg).success}`) 15 | } catch(error) { 16 | await m._reply(error.message) 17 | } 18 | } 19 | } 20 | 21 | const msg = { 22 | id: { 23 | ex: 'Sebut (mention) atau balas pesan orang yang ingin di-unblockir.', 24 | success: 'orang telah berhasil di-unblockir.', 25 | }, 26 | en: { 27 | ex: 'Mention or reply to the message of the person you want to unblock.', 28 | success: 'person has been successfully unblocked.' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/command/owner/unreg.js: -------------------------------------------------------------------------------- 1 | const db = require("../../utils/db.js") 2 | const moment = require("../../utils/moment.js") 3 | 4 | module.exports = { 5 | name: "info-unregister-user", 6 | description: "Unregister User", 7 | cmd: ['unreg'], 8 | run: async ({ m, sock }) => { 9 | if(!m.senderIsOwner) return 10 | let id; 11 | if(m.quoted) id = m.quoted.sender; 12 | else if(m.mentionedJid.length) id = m.mentionedJid[0]; 13 | else return m._reply(m.lang(msg).ex); 14 | const user = await db.user.get(id); 15 | if(!user) return m._reply(m.lang(msg).userNotFound); 16 | await db.user.remove(id); 17 | await m._reply(m.lang(msg).success.replace('{name}', user.name)); 18 | } 19 | } 20 | 21 | const msg = { 22 | id: { 23 | ex: 'penggunaan: {prefix}unreg `@mention`', 24 | success: '{name} telah di hapus dari database.', 25 | userNotFound: 'user tidak ditemukan.' 26 | }, 27 | en: { 28 | ex: 'usage: {prefix}unreg `@mention`', 29 | success: '{name} has been removed from database.', 30 | userNotFound: 'user not found.' 31 | } 32 | } -------------------------------------------------------------------------------- /src/command/store/limit.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const config = require('../../../config.js') 4 | const currency = require('../../utils/currency.js') 5 | const { BlockchainDB, Transaction } = require('../../utils/blockchain/index.js'); 6 | const db = require('../../utils/db.js'); 7 | const blockchain = new BlockchainDB(); 8 | 9 | module.exports = { 10 | name: "store-limit", 11 | description: "Store Limit", 12 | cmd: [ 'buylimit' ], 13 | menu: { 14 | label: 'store' 15 | }, 16 | run: async ({ m, sock }) => { 17 | let list = '*\`❖ List Limit For Sale\`* \n' 18 | list += `> Purchase uses Blockchain\n\n` 19 | list += `*\`1\`* 10 Limit \`100.000 Coin\`\n` 20 | list += `*\`2\`* 25 Limit \`200.000 Coin\`\n` 21 | list += `*\`3\`* 50 Limit \`450.000 Coin\`\n` 22 | list += `*\`4\`* 100 Limit \`800.000 Coin\`\n` 23 | list += `*\`5\`* 150 Limit \`1.000.000 Coin\`\n` 24 | list += `\n` 25 | list += `> If you want to buy limit, please use command ${m.body.prefix}buylimit \`number\`` 26 | if(!m.body.arg.trim()) { 27 | return m._sendMessage(m.chat, { 28 | text: list, 29 | contextInfo: { 30 | mentionedJid: [], 31 | externalAdReply: { 32 | title: `❖ Store Blockchain`, 33 | body: `▷ Limit`, 34 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 35 | sourceUrl: 'https://ilsya.my.id', 36 | mediaType: 1, 37 | } 38 | } 39 | }, { quoted: m }) 40 | } 41 | 42 | let number = m.body.arg.replace(/[^0-9]/g, '') 43 | 44 | let limit = 0, coin = 0; 45 | switch (Number(number)) { 46 | case 1: 47 | limit = 10 48 | coin = 100000 49 | break; 50 | case 2: 51 | limit = 25 52 | coin = 200000 53 | break; 54 | case 3: 55 | limit = 50 56 | coin = 450000 57 | break; 58 | case 4: 59 | limit = 100 60 | coin = 800000 61 | break; 62 | case 5: 63 | limit = 150 64 | coin = 1000000 65 | break; 66 | default: 67 | return m._reply(m.lang(msg).notFound) 68 | break; 69 | } 70 | if(!limit || !coin) return m._reply(m.lang(msg).notFound); 71 | try { 72 | const transfer = await blockchain.transfer(m.sender, 'unknown@s.whatsapp.net', coin); 73 | db.update(db.user, m.sender, { limit: (parseInt(m.db.user.limit) + parseInt(limit)) }) 74 | let text = `*\`❖ Buy Limit\`*\n\n` 75 | text += `▷ *ID Transaction*: ${transfer.txId}\n` 76 | text += `▷ *Limit*: ${limit}\n` 77 | text += `▷ *Price*: ${currency.format(transfer.amount)} coin\n` 78 | text += `▷ *Status*: Success\n` 79 | m._sendMessage(m.chat, { 80 | text: text, 81 | contextInfo: { 82 | mentionedJid: [], 83 | externalAdReply: { 84 | title: `❖ Store Blockchain`, 85 | body: `▷ Limit`, 86 | thumbnail: fs.readFileSync(path.join(config.STORAGE_PATH, 'media/coin.jpg')), 87 | sourceUrl: 'https://ilsya.my.id', 88 | mediaType: 1, 89 | } 90 | } 91 | }, { quoted: m }) 92 | } catch (error) { 93 | if(error.message == 'Saldo tidak cukup!') return m._reply(m.lang(msg).saldoNotEnough) 94 | return m._reply(m.lang(msg).ex) 95 | } 96 | } 97 | } 98 | 99 | const msg = { 100 | id: { 101 | notFound: 'Berikan pilihan yang ada di list.', 102 | saldoNotEnough: 'Coin kamu tidak cukup.', 103 | }, 104 | en: { 105 | notFound: 'Please choose from the list.', 106 | saldoNotEnough: 'Your blockchain balance is not enough.', 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/command/test.js: -------------------------------------------------------------------------------- 1 | const { createCanvas, loadImage } = require('canvas'); 2 | const { jidDecode, downloadContentFromMessage, downloadMediaMessage, generateWAMessageFromContent } = require('@whiskeysockets/baileys'); 3 | const db = require('../utils/db'); 4 | const { default: axios } = require('axios'); 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | const config = require('../../config'); 8 | const { quax } = require('../utils/uploader.js') 9 | const { BlockchainDB, Transaction } = require('../utils/blockchain/index.js') 10 | const moment = require('../utils/moment.js') 11 | const blockchain = new BlockchainDB() 12 | 13 | module.exports = { 14 | name: "test", 15 | description: "-", 16 | withoutPrefix: true, 17 | cmd: ['test'], 18 | run: async ({ m, sock }) => { 19 | if (!m.senderIsOwner) return; 20 | 21 | return; 22 | 23 | 24 | async function sendList(jid, title, text, buttonText, listSections, quoted, options = {}) { 25 | let img; 26 | 27 | const sections = [...listSections] 28 | 29 | const message = { 30 | interactiveMessage: { 31 | header: { 32 | title: title, 33 | hasMediaAttachment: false, 34 | imageMessage: null, 35 | videoMessage: null 36 | }, 37 | body: { text }, 38 | nativeFlowMessage: { 39 | buttons: [ 40 | { 41 | name: 'single_select', 42 | buttonParamsJson: JSON.stringify({ 43 | title: buttonText, 44 | sections 45 | }) 46 | } 47 | ], 48 | messageParamsJson: '' 49 | } 50 | } 51 | }; 52 | 53 | let msgL = generateWAMessageFromContent(jid, { 54 | viewOnceMessage: { 55 | message 56 | } 57 | }, { userJid: sock.user.jid, quoted }) 58 | 59 | return sock.relayMessage(jid, msgL.message, { messageId: msgL.key.id, ...options }) 60 | } 61 | 62 | let listSections = []; 63 | listSections.push({ 64 | title: `✎ LABEL GROUP`, highlight_label: `Popular`, 65 | rows: [ 66 | { 67 | header: "𓆩࿔ྀુ⃟🌹⃟𝘼𝙐𝙏𝙊 𝙑𝙀𝙍𝙄𝙁𝙄𝘾𝘼𝙍 ╎✅", 68 | title: "", 69 | description: `🗃 Verificacion Automáticamente`, 70 | id: `#reg`, 71 | }, 72 | { 73 | header: "𓆩࿔ྀુ⃟🌹⃟𝙈𝙀𝙉𝙐 𝘾𝙊𝙈𝙋𝙇𝙀𝙏𝙊 ╎ 🍿ꪳ͢", 74 | title: "", 75 | description: `🐢 Muestra el menú completo.`, 76 | id: `#allmenu`, 77 | }, 78 | { 79 | header: "𓆩࿔ྀુ⃟🌹⃟𝙈𝙀𝙉𝙐 𝙉𝙎𝙁𝙒 ╎🔞", 80 | title: "", 81 | description: `🔥 Muestra el menú +18.`, 82 | id: `#hornymenu`, 83 | }, 84 | { 85 | header: "𓆩࿔ྀુ⃟🌹⃟𝙂𝙄𝙏𝙃𝙐𝘽 ╎ ⭐️", 86 | title: "", 87 | description: `🍟 Muestra el github de la bot.`, 88 | id: `#sc`, 89 | }, 90 | { 91 | header: "𓆩࿔ྀુ⃟🌹⃟𝙎𝙆𝙔 𝙐𝙇𝙏𝙍𝘼 𝙋𝙇𝙐𝙎 ╎ 💸", 92 | title: "", 93 | description: `⚡️ Super hosting, Sky Ultra Plus.`, 94 | id: `#skyplus`, 95 | }, 96 | { 97 | header: "𓆩࿔ྀુ⃟🌹⃟𝙎𝙋𝙀𝙀𝘿 ╎ 🌸", 98 | title: "", 99 | description: `🚀 Muestra su velocidad y mas.`, 100 | id: `#speed`, 101 | }, 102 | { 103 | header: "𓆩࿔ྀુ⃟🌹⃟𝙎𝙀𝙍𝘽𝙊𝙏 𝘾𝙊𝘿𝙀 ╎ ⚡️", 104 | title: "", 105 | description: `🍟 Ser subbot mediante un codigo de 8 digitos.`, 106 | id: `#code`, 107 | }, 108 | { 109 | header: "𓆩࿔ྀુ⃟🌹⃟𝙎𝙀𝙍𝘽𝙊𝙏 𝙌𝙍 ╎ 📂", 110 | title: "", 111 | description: `☁️ Ser subbot mediante un codigo QR.`, 112 | id: `#serbot`, 113 | }, 114 | { 115 | header: "𓆩࿔ྀુ⃟🌹⃟𝙎𝙐𝘽𝘽𝙊𝙏𝙎 ╎ 🚩", 116 | title: "", 117 | description: `🟢 Muestra su subbots onlines.`, 118 | id: `#bots`, 119 | }, 120 | { 121 | header: "𓆩࿔ྀુ⃟🌹⃟𝙂𝙍𝙐𝙋𝙊𝙎 ☁️", 122 | title: "", 123 | description: `📲 Muestra los grupos principales de la bot.`, 124 | id: `/help`, 125 | }, 126 | ], 127 | }); 128 | 129 | await sendList( 130 | m.chat, 131 | 'Nakiri Whatsapp BOT', 132 | 'Selamat Datang Di Nakiri Whatsapp BOT', 133 | 'MENU', 134 | listSections, 135 | m 136 | ) 137 | } 138 | } 139 | 140 | -------------------------------------------------------------------------------- /src/command/tools/attp.js: -------------------------------------------------------------------------------- 1 | const { attp } = require('../../utils/attp.js') 2 | const { writeExifVid } = require("../../utils/stickerMaker"); 3 | const exp = require('../../utils/exp.js'); 4 | const fs = require('fs') 5 | 6 | module.exports = { 7 | name : "sticker-attp", 8 | description : "Sticker Attp", 9 | cmd : ['attp'], 10 | menu : { 11 | label : 'tools', 12 | }, 13 | run : async({ m, sock }) => { 14 | if(!m.body.arg) return m._reply(m.lang(msg).ex) 15 | 16 | try { 17 | m._react(m.key, '🧋') 18 | let sticker = await attp(m.body.arg) 19 | sticker = await writeExifVid(fs.readFileSync(sticker), { packname : m.db.bot.exif.pack || '-', author : m.db.bot.exif.author || '-' }) 20 | exp.add(m.sender, exp.random(1, 5)) 21 | await m._sendMessage(m.chat, { sticker : sticker }, { quoted: m }) 22 | m._react(m.key, '✅') 23 | } catch(error) { 24 | m._react(m.key, '❌') 25 | await m._reply(error.message) 26 | } 27 | } 28 | } 29 | 30 | const msg = { 31 | id: { 32 | ex: '*Penggunaan*: {prefix}attp `text`', 33 | }, 34 | en: { 35 | ex: '*Usage*: {prefix}attp `text`', 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/command/tools/nobg.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios"); 2 | const { imageToWebp, writeExifImg, videoToWebp, writeExifVid } = require("../../utils/stickerMaker"); 3 | const validateUrl = require("../../utils/validate-url.js"); 4 | const exp = require('../../utils/exp.js'); 5 | const uploader = require('../../utils/uploader.js'); 6 | 7 | module.exports = { 8 | name : "sticker-nobg", 9 | description : "Sticker No Background", 10 | cmd : ['nobg'], 11 | menu : { 12 | label : 'tools', 13 | }, 14 | run : async({ m, sock }) => { 15 | let url = validateUrl(m.body.arg) ? m.body.arg : false 16 | let image; 17 | if(!['imageMessage', 'stickerMessage'].includes(m.quoted?.mtype || m.mtype) && !url) return m._reply(m.lang(msg).ex); 18 | m._react(m.key, '🧋') 19 | if(url) { 20 | try { 21 | image = await axios.get(url, { responseType: 'arraybuffer' }) 22 | }catch(error) { return m._reply(m.lang(msg).invalidUrl) } 23 | if(!['video', 'image'].includes(image.headers.get('content-type').split('/')[0])) return m._reply(m.lang(msg).req) 24 | image = { 25 | buffer : image.data, 26 | ext : image.headers.get('content-type').split('/')[1], 27 | mtype : image.headers.get('content-type').split('/')[0]+'Message' 28 | } 29 | } else { 30 | image = m.quoted ? await m.quoted.download() : await m.download(); 31 | } 32 | 33 | if(image.mtype === 'imageMessage' || image.mtype === 'stickerMessage') { 34 | let sticker = await uploader.quax(image.buffer); 35 | sticker = (await axios.get(`https://api.nyxs.pw/tools/removebg?url=${sticker}`)).data.result 36 | sticker = await imageToWebp((await axios.get(sticker, { responseType: 'arraybuffer' })).data) 37 | sticker = await writeExifImg(sticker, { packname : m.db.bot.exif.pack || '-', author : m.db.bot.exif.author || '-' }) 38 | exp.add(m.sender, exp.random(1, 5)) 39 | await m._sendMessage(m.chat, { sticker : sticker }, { quoted: m }) 40 | m._react(m.key, '✅') 41 | } else { 42 | m._react(m.key, '❌') 43 | m._reply(m.lang(msg).req) 44 | } 45 | } 46 | } 47 | 48 | const msg = { 49 | id: { 50 | ex: '*Penggunaan*:\n- Balas gambar atau sticker dengan caption `{prefix}nobg`\n- Kirim gambar dengan caption `{prefix}nobg`\n- {prefix}nobg \n\n*Keterangan*:*\n- **: URL berisi gambar.', 51 | req: 'Format yang diperbolehkan: `gambar` atau `stiker`.', 52 | invalidUrl: 'URL tidak valid.' 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /src/command/tools/readmore.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "readmore", 3 | description : "Read More", 4 | cmd : ['readmore', 'spoiler'], 5 | menu : { 6 | label : 'tools', 7 | example : 'text|text' 8 | }, 9 | run : async({ m, sock }) => { 10 | let [l, r] = m.body.arg.split('|'); 11 | if (!l && !r) return m._reply(m.lang(msg).ex); 12 | if (!l) l = ''; 13 | if (!r) r = ''; 14 | const more = String.fromCharCode(8206); 15 | const readMore = more.repeat(4001); 16 | m._reply(l + readMore + r); 17 | } 18 | } 19 | 20 | const msg = { 21 | id: { 22 | ex: 'Penggunaan {prefix}readme |', 23 | }, 24 | en: { 25 | ex: 'Usage {prefix}readme |', 26 | } 27 | } -------------------------------------------------------------------------------- /src/command/tools/sticker.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios"); 2 | const { imageToWebp, writeExifImg, videoToWebp, writeExifVid } = require("../../utils/stickerMaker"); 3 | const validateUrl = require("../../utils/validate-url.js"); 4 | const exp = require('../../utils/exp.js'); 5 | 6 | module.exports = { 7 | name : "sticker", 8 | description : "Sticker Maker", 9 | cmd : ['sticker', 's', 'stiker'], 10 | menu : { 11 | label : 'tools', 12 | }, 13 | run : async({ m, sock }) => { 14 | let url = validateUrl(m.body.arg) ? m.body.arg : false 15 | let image; 16 | if(!['imageMessage', 'stickerMessage', 'videoMessage'].includes(m.quoted?.mtype || m.mtype) && !url) return m._reply(m.lang(msg).ex); 17 | m._react(m.key, '🧋') 18 | if(url) { 19 | try { 20 | image = await axios.get(url, { responseType: 'arraybuffer' }) 21 | }catch(error) { return m._reply(m.lang(msg).invalidUrl) } 22 | if(!['video', 'image'].includes(image.headers.get('content-type').split('/')[0])) return m._reply(m.lang(msg).req) 23 | image = { 24 | buffer : image.data, 25 | ext : image.headers.get('content-type').split('/')[1], 26 | mtype : image.headers.get('content-type').split('/')[0]+'Message' 27 | } 28 | } else { 29 | image = m.quoted ? await m.quoted.download() : await m.download(); 30 | } 31 | 32 | if(image.mtype === 'imageMessage' || image.mtype === 'stickerMessage') { 33 | let sticker = await imageToWebp(image.buffer) 34 | sticker = await writeExifImg(sticker, { packname : m.db.bot.exif.pack || '-', author : m.db.bot.exif.author || '-' }) 35 | exp.add(m.sender, exp.random(1, 5)) 36 | await m._sendMessage(m.chat, { sticker : sticker }, { quoted: m }) 37 | m._react(m.key, '✅') 38 | } else if(image.mtype === 'videoMessage') { 39 | let sticker = await videoToWebp(image.buffer) 40 | sticker = await writeExifVid(sticker, { packname : m.db.bot.exif.pack || '-', author : m.db.bot.exif.author || '-' }) 41 | exp.add(m.sender, exp.random(1, 5)) 42 | await m._sendMessage(m.chat, { sticker : sticker }, { quoted: m }) 43 | m._react(m.key, '✅') 44 | } else { 45 | m._react(m.key, '❌') 46 | m._reply(m.lang(msg).req) 47 | } 48 | } 49 | } 50 | 51 | const msg = { 52 | id: { 53 | ex: '*Penggunaan*:\n- Balas gambar atau sticker dengan caption `{prefix}sticker`\n- Kirim gambar atau video dengan caption `{prefix}sticker`\n- {prefix}sticker \n\n*Keterangan*:*\n- **: URL berisi gambar atau video.', 54 | req: 'Format yang diperbolehkan: `gambar`, `stiker`, atau `video`.', 55 | invalidUrl: 'URL tidak valid.' 56 | }, 57 | en: { 58 | ex: '*Usage:*\n- Reply to an image or sticker with the caption `{prefix}sticker`\n- Send an image or video with the caption `{prefix}sticker`\n- {prefix}sticker \n\n*Description:*\n- **: URL contains image or video.', 59 | req: 'Must be in the format: image, sticker, or video.', 60 | invalidUrl: 'URL is invalid.' 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/command/tools/take.js: -------------------------------------------------------------------------------- 1 | const { imageToWebp, writeExifImg, videoToWebp, writeExifVid } = require("../../utils/stickerMaker"); 2 | 3 | module.exports = { 4 | name : "sticker-take", 5 | description : "Sticker Stealer", 6 | cmd : ['take', 'steal'], 7 | menu : { 8 | label : 'tools', 9 | }, 10 | run : async({ m, sock }) => { 11 | if(!['stickerMessage'].includes(m.quoted?.mtype || m.mtype)) return m._reply(m.lang(msg).ex); 12 | const [pack, author] = m.body.arg.trim().split('|') 13 | if(!pack && !author) return m._reply(m.lang(msg).ex) 14 | try { 15 | let image = m.quoted ? await m.quoted.download() : await m.download(); 16 | m._react(m.key, '🧋') 17 | if(image.mtype === 'imageMessage' || image.mtype === 'stickerMessage') { 18 | let sticker = await imageToWebp(image.buffer) 19 | sticker = await writeExifImg(sticker, { packname : pack, author }) 20 | await m._sendMessage(m.chat, { sticker : sticker }, { quoted: m }) 21 | m._react(m.key, '✅') 22 | } else if(image.mtype === 'videoMessage') { 23 | let sticker = await videoToWebp(image.buffer) 24 | sticker = await writeExifVid(sticker, { packname : pack, author }) 25 | await m._sendMessage(m.chat, { sticker : sticker }, { quoted: m }) 26 | m._react(m.key, '✅') 27 | } 28 | } catch (error) { 29 | m._react(m.key, '❌') 30 | await m._reply(m.lang(msg).failed) 31 | } 32 | } 33 | } 34 | 35 | const msg = { 36 | id: { 37 | ex: '*Penggunaan*: Balas sticker dengan caption `{prefix}take |`\n\n*Keterangan:*\n- **: Nama paket yang akan digunakan untuk exif.\n- **: Nama penulis yang akan digunakan untuk exif.', 38 | failed: 'Stiker tidak valid atau rusak.' 39 | }, 40 | en: { 41 | ex: '*Usage*: Reply to a sticker with the caption `{prefix}take |`\n\n*Description:*\n- **: The pack name to be used for exif.\n- **: The author name to be used for exif.', 42 | failed: 'Sticker is invalid or corrupted.' 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/command/tools/toimg.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name : "toimg", 3 | description : "Sticker To Image", 4 | cmd : ['toimg'], 5 | menu : { 6 | label : 'tools', 7 | example : 'reply sticker' 8 | }, 9 | run : async({ m, sock }) => { 10 | if(!['stickerMessage'].includes(m.quoted?.mtype)) return m._reply(m.lang(msg).ex); 11 | try { 12 | m._react(m.key, '🧋') 13 | let image = await m.quoted.download() 14 | await m._sendMessage(m.chat, { image: image.buffer }, { quoted: m }) 15 | m._react(m.key, '✅') 16 | } catch (error) { 17 | m._react(m.key, '❌') 18 | await m._reply(m.lang(msg).failed) 19 | } 20 | } 21 | } 22 | 23 | const msg = { 24 | id: { 25 | ex: 'Balas dengan stiker.', 26 | failed: 'Stiker tidak valid atau rusak.' 27 | }, 28 | en: { 29 | ex: 'Reply with a sticker.', 30 | failed: 'Sticker is invalid or corrupted.' 31 | } 32 | } -------------------------------------------------------------------------------- /src/command/tools/tovid.js: -------------------------------------------------------------------------------- 1 | const config = require("../../../config.js") 2 | const path = require("path") 3 | const { webpToVideo } = require('../../utils/stickerMaker.js') 4 | 5 | module.exports = { 6 | name : "tovid", 7 | description : "Sticker To Video", 8 | cmd : ['tovid', 'tovideo'], 9 | menu : { 10 | label : 'tools', 11 | example : 'reply sticker' 12 | }, 13 | run : async({ m, sock }) => { 14 | if(!['stickerMessage'].includes(m.quoted?.mtype)) return m._reply(m.lang(msg).ex); 15 | try { 16 | m._react(m.key, '🧋') 17 | let media = await m.quoted.saveMedia(path.join(config.STORAGE_PATH, 'temp')) 18 | let video = await webpToVideo(media) 19 | await m._sendMessage(m.chat, { video }, { quoted: m }) 20 | m._react(m.key, '✅') 21 | } catch (error) { 22 | m._react(m.key, '❌') 23 | await m._reply(m.lang(msg).failed) 24 | } 25 | } 26 | } 27 | 28 | const msg = { 29 | id: { 30 | ex: 'Balas dengan stiker.', 31 | failed: 'Stiker tidak valid atau rusak.' 32 | }, 33 | en: { 34 | ex: 'Reply with a sticker.', 35 | failed: 'Sticker is invalid or corrupted.' 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/middleware/activity-record.js: -------------------------------------------------------------------------------- 1 | // Activity Record For Member Group 2 | const db = require("../utils/db.js") 3 | const moment = require("../utils/moment.js") 4 | const lastMessageMap = new Map(); 5 | const spamInterval = 60000; // milliseconds 6 | const exp = require('../utils/exp.js'); 7 | 8 | module.exports = { 9 | handler : async (sock, m, $next) => { 10 | if(m.fromMe) return $next 11 | if(!m.isGroup) return $next 12 | if(!m.db?.group?.activity_record) return $next 13 | 14 | const key = `${m.isGroup.groupMetadata.id}-${m.sender}`; 15 | const currentTime = moment(); 16 | 17 | for (const [k, lastMessageTime] of lastMessageMap) { 18 | if (currentTime.diff(lastMessageTime, 'milliseconds') >= spamInterval) { 19 | lastMessageMap.delete(k); 20 | } 21 | } 22 | 23 | if(lastMessageMap.has(key)) { 24 | const lastMessageTime = lastMessageMap.get(key); 25 | if(currentTime.diff(lastMessageTime, 'milliseconds') < spamInterval) { 26 | // console.log(`Spam detected: ${key} - expired in ${currentTime.diff(lastMessageTime, 'seconds')} seconds`); 27 | return $next; 28 | } 29 | } 30 | 31 | lastMessageMap.set(key, currentTime); 32 | 33 | try { 34 | exp.add(m.sender, exp.random(1, 5)); 35 | db.update(db.group, m.isGroup.groupMetadata.id, { 36 | member_activity: { 37 | ...(m.db.group.member_activity || {}), 38 | [m.sender]: (m.db.group.member_activity?.[m.sender] || 0) + 1 39 | }, 40 | updated_at: moment() 41 | }); 42 | } catch(err) { 43 | console.error("Middleware Activity Record Error: "+err) 44 | } 45 | 46 | return $next; 47 | } 48 | } -------------------------------------------------------------------------------- /src/middleware/antilink.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | handler : async (sock, m, $next) => { 3 | if(m.fromMe) return $next 4 | if(!m.isGroup) return $next 5 | if(!m.db?.group?.antilink) return $next 6 | if(!m.isGroup.botIsAdmin) return $next 7 | if(m.isGroup.senderIsAdmin) return $next 8 | if(!m.body.full.match(`chat.whatsapp.com`)) return $next 9 | const currentGroupLink = (`https://chat.whatsapp.com/` + await sock.groupInviteCode(m.chat)) 10 | if(m.body.full.match(currentGroupLink)) return $next 11 | // hapus pesan 12 | await sock.sendMessage(m.chat, { delete: m.key }) 13 | return $next; 14 | } 15 | } -------------------------------------------------------------------------------- /src/middleware/antinfsw-media.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios"); 2 | 3 | module.exports = { 4 | handler : async (sock, m, $next) => { 5 | try { 6 | return $next; 7 | if(!m.isGroup) return $next 8 | if(!['imageMessage'].includes(m.mtype)) return $next; 9 | const { buffer } = await m.download() 10 | const response = await axios.post('https://luminai.my.id/', { 11 | imageBuffer: buffer, 12 | model: 'gpt-4o', 13 | content : `Anda adalah asisten di sebuah komunitas WhatsApp yang memiliki tanggung jawab untuk memfilter gambar. Tugas utama Anda adalah mengidentifikasi apakah gambar yang dikirim dalam grup berisi konten pornografi atau tidak. 14 | 15 | Berikut adalah panduan yang harus Anda ikuti: 16 | 17 | 1. Jika gambar yang Anda terima mengandung konten pornografi, balas dengan "yes". 18 | 2. Jika gambar tersebut tidak mengandung konten pornografi, balas dengan "no". 19 | 3. Jika Anda merasa ragu atau tidak yakin tentang konten gambar tersebut, balas dengan "no". 20 | 4. Jangan memberikan jawaban selain "yes" atau "no". 21 | Pastikan untuk selalu berhati-hati dalam menilai konten gambar, dan hindari memberikan penilaian yang tidak sesuai.` 22 | }); 23 | 24 | if(response.data.result.length == 0) { 25 | await m._reply('Gambar yang Anda kirim mengandung konten pornografi.') 26 | await sock.sendMessage(m.chat, { delete: m.key }) 27 | } 28 | } catch (err) { 29 | console.error(err); 30 | } 31 | 32 | return $next; 33 | } 34 | } -------------------------------------------------------------------------------- /src/middleware/app.js: -------------------------------------------------------------------------------- 1 | const middleware = new Map(); 2 | 3 | middleware.set('antilink.js', require('./antilink.js')) 4 | middleware.set('activity-record.js', require('./activity-record.js')) 5 | middleware.set('timeout-expired.js', require('./timeout-expired.js')) 6 | middleware.set('timeout.js', require('./timeout.js')) 7 | middleware.set('bot-mode.js', require('./bot-mode.js')) 8 | middleware.set('group-mode.js', require('./group-mode.js')) 9 | middleware.set('register.js', require('./register.js')) 10 | middleware.set('limit.js', require('./limit.js')) 11 | middleware.set('blackjack.js', require('./blackjack.js')) 12 | middleware.set('tictactoe.js', require('./tictactoe.js')) 13 | middleware.set('nakiri.js', require('./nakiri.js')) 14 | // middleware.set('antinfsw-media.js', require('./antinfsw-media.js')) 15 | 16 | module.exports = middleware -------------------------------------------------------------------------------- /src/middleware/blackjack.js: -------------------------------------------------------------------------------- 1 | const { 2 | bjMap, 3 | formatCard, 4 | formatHand, 5 | calculateHandValue, 6 | addReactions 7 | } = require('../utils/games/blackjack.js'); 8 | const currency = require('../utils/currency.js'); 9 | 10 | module.exports = { 11 | handler : async (sock, m, $next) => { 12 | if(m.fromMe) return $next 13 | try { 14 | const game = bjMap.get(m.sender) 15 | if(!game || game.status !== 'playing') return $next 16 | 17 | if (m.body.commandWithoutPrefix === 'hit') { 18 | addReactions(sock, m.key, 'hit'); 19 | game.playerHand.push(game.deck.pop()); 20 | const handValue = calculateHandValue(game.playerHand); 21 | 22 | if (handValue > 21) { 23 | game.status = 'finished'; 24 | let text = `_*${m.db.user.name}*, you bet *${currency.format(game.bet)}* to play blackjack._\n\n`; 25 | text += `> *Your hand*: _${formatHand(game.playerHand)}_ *\`[${handValue}]\`*\n\n`; 26 | text += `🎲 ~ \`You lose!\`\n\n`; 27 | text += `Type !blackjack to play again.`; 28 | await m._sendMessage(m.chat, { text }, { quoted: m }); 29 | bjMap.delete(m.sender); 30 | } else { 31 | let text = `_*${m.db.user.name}*, you bet *${currency.format(game.bet)}* to play blackjack._\`\n\n`; 32 | text += `> *Your hand*: _${formatHand(game.playerHand)}_ *\`[${handValue}]\`*\n`; 33 | text += `> *Dealer's hand*: _${formatCard(game.dealerHand[0])}_ *\`[${calculateHandValue(game.dealerHand)}+?]\`*\n\n`; 34 | text += m.lang(msg).desc; 35 | await m._sendMessage(m.chat, { text }, { quoted: m }); 36 | } 37 | } 38 | 39 | if (m.body.commandWithoutPrefix === 'stand') { 40 | addReactions(sock, m.key, 'stand'); 41 | let dealerValue = calculateHandValue(game.dealerHand); 42 | while (dealerValue < 17) { 43 | game.dealerHand.push(game.deck.pop()); 44 | dealerValue = calculateHandValue(game.dealerHand); 45 | } 46 | const playerValue = calculateHandValue(game.playerHand); 47 | let winer; 48 | 49 | if (dealerValue > 21) { 50 | winer = 'You win! Dealer bust! 🎉'; 51 | currency.updateBalanceUser(m.sender, currency.add(m.db.user.balance, parseInt(game.bet) * 2)); 52 | } else if (dealerValue > playerValue) { 53 | winer = 'Dealer wins! 🤓'; 54 | } else if (playerValue > dealerValue) { 55 | winer = 'You win! 🎉'; 56 | currency.updateBalanceUser(m.sender, currency.add(m.db.user.balance, parseInt(game.bet) * 2)); 57 | } else { 58 | winer = "It's a tie! 🤝"; 59 | currency.updateBalanceUser(m.sender, currency.add(m.db.user.balance, parseInt(game.bet))); 60 | } 61 | 62 | let text = `_*${m.db.user.name}*, you bet *${currency.format(game.bet)}* to play blackjack._\n\n`; 63 | text += `> *Your hand*: _${formatHand(game.playerHand)}_ *\`[${playerValue}]\`*\n`; 64 | text += `> *Dealer's hand*: _${formatHand(game.dealerHand)}_ *\`[${dealerValue}]\`*\n\n`; 65 | text += `🎲 ~ \`${winer}\`\n\n`; 66 | text += '```Type !blackjack to play again.```'; 67 | await m._sendMessage(m.chat, { text }, { quoted: m }); 68 | bjMap.delete(m.sender); 69 | } 70 | 71 | } catch (error) { 72 | console.error(error) 73 | } 74 | 75 | return $next; 76 | } 77 | } 78 | 79 | const msg = { 80 | id: { 81 | desc: '```Tipe``` *`hit`* ```untuk mengambil kartu lain atau``` *`stand`* ```untuk mempertahankan kartu Anda saat ini.```' 82 | }, 83 | en: { 84 | desc: '```Type``` *`hit`* ```to take another card or``` *`stand`* ```to keep your current hand.```' 85 | } 86 | } -------------------------------------------------------------------------------- /src/middleware/bot-mode.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | handler : async (sock, m, $next) => { 3 | if(!m.senderIsOwner && m.db.bot.mode == 'private') { 4 | throw { 5 | break: true, 6 | continueCommand: false, 7 | message: 'Bot hanya dapat merespon ke owner', 8 | hideLogs: true 9 | }; 10 | } 11 | return $next; 12 | } 13 | } -------------------------------------------------------------------------------- /src/middleware/group-mode.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | handler : async (sock, m, $next) => { 3 | if (m.isGroup && !m.senderIsOwner && m.db.group.mode === 'admin-only' && !m.isGroup.senderIsAdmin) { 4 | throw { 5 | break: true, 6 | continueCommand: false, 7 | message: 'Bot hanya dapat merespon ke admin', 8 | hideLogs: true 9 | }; 10 | } 11 | return $next; 12 | } 13 | } -------------------------------------------------------------------------------- /src/middleware/limit.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | handler : async (sock, m, $next, command) => { 3 | if(m.fromMe) return $next 4 | if(!command) return $next 5 | if(!command.limit) return $next 6 | if(m.db.user?.limit == 'unlimited') return $next 7 | 8 | if (parseInt(m.db.user.limit) < command.limit) { 9 | m._reply(`Limit tidak mencukupi. Kamu butuh ${command.limit} limit.\nKetik \`${m.body.prefix}buylimit\` untuk membeli limit, atau klaim limit harian dengan \`${m.body.prefix}daily\`.`); 10 | throw { 11 | break: false, 12 | continueCommand: false, 13 | message: 'No enough limit, you need ' + command.limit + ' limit.\nType `'+m.body.prefix+'buylimit` to buy limit.', 14 | hideLogs: true 15 | } 16 | } 17 | 18 | return $next; 19 | } 20 | } -------------------------------------------------------------------------------- /src/middleware/register.js: -------------------------------------------------------------------------------- 1 | const moment = require('../utils/moment.js'); 2 | const config = require('../../config.js'); 3 | const db = require('../utils/db.js'); 4 | 5 | const intended = new Map(); 6 | const expiredIntended = 60; // seconds 7 | 8 | module.exports = { 9 | handler : async (sock, m, $next, command) => { 10 | if(m.fromMe) return $next 11 | 12 | // if user not register and try command bot 13 | if (!m.db?.user && m.body.prefix) { 14 | // if user try to register 15 | if(m.body.commandWithoutPrefix == 'reg' && m.body.arg) { 16 | const name = m.body.arg.replace(/[^A-Za-z ]/g, ''); 17 | if(name.length < 3) return m._reply(m.lang(msg).min); 18 | if(['admin', 'owner', 'nama', 'name', 'bot', 'asw'].includes(name)) return m._reply(m.lang(msg).tol); 19 | console.log('Registering User : ' + name); 20 | await db.user.put(m.sender, { name, ...config.DATABASE_SCHEMA.user}) 21 | intended.delete(m.sender); 22 | m._reply(m.lang(msg).success.replace('{name}', name)); 23 | } else if (!intended.has(m.sender) || moment().isAfter(intended.get(m.sender).expired) && command) { 24 | intended.set(m.sender, { 25 | command: m.body.commandWithoutPrefix, 26 | expired: moment().add(expiredIntended, 'seconds') 27 | }); 28 | m._reply(m.lang(msg).register); 29 | } 30 | 31 | throw { 32 | break: false, // continue code 33 | continueCommand: false, // but dont execute command 34 | message: 'User has not registered.', 35 | hideLogs: true 36 | } 37 | } 38 | 39 | return $next; 40 | } 41 | } 42 | 43 | const msg = { 44 | id : { 45 | register : 'Silahkan lakukan registrasi terlebih dahulu.\nCaranya ketik {prefix}reg `nama`', 46 | success : 'Hai *{name}* silahkan menggunakan bot dengan bijak.\n\nUntuk mengecek profile ketik `{prefix}id`\nUntuk menampilkan semua fitur bot ketik `{prefix}help`', 47 | min: 'Minimal 3 huruf.', 48 | tol: 'Yang bener napa bikin nama 🥱, cari nama lain le.' 49 | }, 50 | en : { 51 | register : 'Please register first.\nHow to register : {prefix}reg `name`', 52 | success : 'Hi *{name}* please use the bot with caution.\n\nTo check profile type `{prefix}id`\nTo show all features type `{prefix}help`', 53 | min: 'Minimal 3 character.', 54 | tol: 'Name cannot be used 🥱' 55 | } 56 | } -------------------------------------------------------------------------------- /src/middleware/timeout-expired.js: -------------------------------------------------------------------------------- 1 | const db = require('../utils/db.js'); 2 | const moment = require('../utils/moment.js'); 3 | 4 | module.exports = { 5 | handler : async (sock, m, $next) => { 6 | if(m.fromMe) return $next; 7 | if(!m.isGroup) return $next; 8 | 9 | let timeouts = { ...m.db.group?.timeouts || {} }; 10 | let hasExpired = false; 11 | 12 | for (const [key, value] of Object.entries(timeouts)) { 13 | if (moment().isAfter(value)) { 14 | delete timeouts[key]; 15 | hasExpired = true; 16 | } 17 | } 18 | 19 | if (hasExpired) { 20 | m.db.group.timeouts = timeouts; 21 | db.update(db.group, m.isGroup.groupMetadata.id, { 22 | timeouts 23 | }); 24 | } 25 | 26 | 27 | return $next; 28 | } 29 | } -------------------------------------------------------------------------------- /src/middleware/timeout.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | handler : async (sock, m, $next) => { 3 | if(m.fromMe) return $next 4 | if(!m.isGroup) return $next 5 | if(!m.db?.group?.timeouts) return $next 6 | if(!m.isGroup.botIsAdmin) return $next 7 | if(m.isGroup.senderIsAdmin) return $next 8 | 9 | if(Object.keys(m.db.group?.timeouts || {}).find(x => x == m.sender)) { 10 | await sock.sendMessage(m.chat, { delete: m.key }) 11 | throw { 12 | break: false, 13 | continueCommand: false, 14 | message: 'Kamu sedang timeout di grup ini', 15 | } 16 | } 17 | 18 | return $next; 19 | } 20 | } 21 | 22 | 23 | /* 24 | break: 25 | jika true dia tidak akan menjalankan middleware selanjutnya. 26 | jika false dia tetap akan menjalankan middleware selanjutnya. 27 | 28 | continueCommand: 29 | jika true dia akan tetap akan menjalankan command 30 | jika false dia tidak akan menjalankan command 31 | 32 | throw { 33 | break: true, 34 | continueCommand: false, 35 | message: 'Kamu sedang timeout di grup ini', 36 | } 37 | */ -------------------------------------------------------------------------------- /src/utils/attp.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const ffmpeg = require('fluent-ffmpeg') 3 | const Crypto = require('crypto') 4 | const { UltimateTextToImage } = require('ultimate-text-to-image') 5 | const path = require('path') 6 | const config = require('../../config.js') 7 | 8 | async function attp(text) { 9 | let nome = randomName() 10 | let cores = [ 11 | '#ff0000', 12 | '#ffa600', 13 | '#ffee00', 14 | '#2bff00', 15 | '#00ffea', 16 | '#3700ff', 17 | '#ff00ea', 18 | ] 19 | 20 | const lista = cores.map((cor, index) => { 21 | return ttp(text, cor, nome + index + '.png') 22 | }) 23 | 24 | return new Promise(function (resolve, reject) { 25 | // gerar webp 26 | ffmpeg() 27 | .addInput((nome + '%d.png')) 28 | .addOutputOptions([ 29 | '-vcodec', 'libwebp', '-vf', 30 | 'scale=500:500:force_original_aspect_ratio=decrease,setsar=1, pad=500:500:-1:-1:color=white@0.0, split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse', 31 | '-loop', '0', '-preset', 'default' 32 | ]) 33 | //.outputFPS(15) 34 | .toFormat('webp') 35 | .on('end', () => { 36 | for (let img of lista) { 37 | delFile(img) 38 | } 39 | resolve(nome + '.webp') 40 | }) 41 | .on('error', (err) => { 42 | for (let img of lista) { 43 | delFile(img) 44 | } 45 | reject(('erro ffmpeg ' + err)) 46 | }) 47 | .save((nome + '.webp')) 48 | }) 49 | } 50 | 51 | function ttp(text, color = '#ffffff', name = randomName('.png')) { 52 | new UltimateTextToImage(text, { 53 | width: 500, 54 | height: 500, 55 | fontColor: color, 56 | fontFamily: "Sans-Serif", 57 | fontSize: 600, 58 | minFontSize: 10, 59 | lineHeight: 0, 60 | autoWrapLineHeightMultiplier: 1.2, 61 | margin: 0, 62 | // marginBottom: 40, 63 | align: "center", 64 | valign: "middle", 65 | }) 66 | .render() 67 | .toFile(name); 68 | 69 | return name 70 | } 71 | 72 | function randomName(ext = '') { 73 | return path.join(config.STORAGE_PATH+'/temp', `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}${ext}`) 74 | } 75 | 76 | function delFile(file) { 77 | try { 78 | fs.unlinkSync(file) 79 | } catch (error) { 80 | 81 | } 82 | } 83 | 84 | module.exports = { 85 | attp, 86 | ttp 87 | } -------------------------------------------------------------------------------- /src/utils/blockchain/block.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | 3 | class Block { 4 | constructor(timestamp, transactions, previousHash = '') { 5 | this.timestamp = timestamp; 6 | this.transactions = transactions; 7 | this.previousHash = previousHash; 8 | this.hash = this.calculateHash(); 9 | this.nonce = 0; 10 | } 11 | 12 | calculateHash() { 13 | return crypto 14 | .createHash('sha256') 15 | .update( 16 | this.previousHash + 17 | this.timestamp + 18 | JSON.stringify(this.transactions) + 19 | this.nonce 20 | ) 21 | .digest('hex'); 22 | } 23 | 24 | mineBlock(difficulty) { 25 | while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) { 26 | this.nonce++; 27 | this.hash = this.calculateHash(); 28 | } 29 | } 30 | } 31 | 32 | module.exports = Block -------------------------------------------------------------------------------- /src/utils/blockchain/index.js: -------------------------------------------------------------------------------- 1 | const db = require('../db.js'); 2 | const crypto = require('crypto'); 3 | const moment = require('../moment.js'); 4 | 5 | class Transaction { 6 | constructor(fromAddress, toAddress, amount) { 7 | this.fromAddress = fromAddress; 8 | this.toAddress = toAddress; 9 | this.amount = amount; 10 | this.timestamp = moment(); 11 | } 12 | } 13 | 14 | class BlockchainDB { 15 | constructor() { 16 | this.db = db.blockchain; 17 | } 18 | 19 | async getMetadata() { 20 | return await this.db.metadata.get('blockchainInfo'); 21 | } 22 | async transfer(fromAddress, toAddress, amount) { 23 | try { 24 | // Validasi saldo 25 | const senderBalance = await this.getBalance(fromAddress); 26 | if (amount > senderBalance) { 27 | throw new Error('Saldo tidak cukup!'); 28 | } 29 | 30 | // Update saldo pengirim dan penerima 31 | await this.updateBalance(fromAddress, -amount); 32 | await this.updateBalance(toAddress, amount); 33 | 34 | // Buat ID transaksi 35 | const txId = crypto.randomBytes(16).toString('hex'); 36 | 37 | // Simpan history transaksi 38 | await this.db.txHistory.put(txId, { 39 | id: txId, 40 | from: fromAddress, 41 | to: toAddress, 42 | amount: amount, 43 | timestamp: moment(), 44 | type: 'transfer' 45 | }); 46 | 47 | // Update total transaksi 48 | const metadata = await this.getMetadata(); 49 | await this.db.metadata.put('blockchainInfo', { 50 | ...metadata, 51 | totalTransactions: metadata.totalTransactions + 1 52 | }); 53 | 54 | return { 55 | success: true, 56 | txId, 57 | from: fromAddress, 58 | to: toAddress, 59 | amount: amount 60 | }; 61 | } catch (error) { 62 | throw error; 63 | } 64 | } 65 | 66 | // Fungsi mining terpisah 67 | async mine(minerAddress) { 68 | // Validasi maximum supply 69 | const metadata = await this.getMetadata(); 70 | const currentReward = await this.calculateCurrentReward(); 71 | 72 | if (metadata.currentSupply + currentReward > metadata.maxSupply) { 73 | throw new Error('Maksimum supply tercapai!'); 74 | } 75 | 76 | // Update saldo miner 77 | await this.updateBalance(minerAddress, currentReward); 78 | 79 | // Update metadata 80 | await this.db.metadata.put('blockchainInfo', { 81 | ...metadata, 82 | currentSupply: metadata.currentSupply + currentReward, 83 | blocksMined: metadata.blocksMined + 1 84 | }); 85 | 86 | // Catat mining reward sebagai transaksi 87 | const txId = crypto.randomBytes(16).toString('hex'); 88 | await this.db.txHistory.put(txId, { 89 | id: txId, 90 | from: 'SYSTEM', 91 | to: minerAddress, 92 | amount: currentReward, 93 | timestamp: moment(), 94 | type: 'mining_reward' 95 | }); 96 | 97 | return { 98 | success: true, 99 | reward: currentReward, 100 | remainingSupply: metadata.maxSupply - (metadata.currentSupply + currentReward), 101 | blocksUntilHalving: metadata.blockRewardHalvingInterval - ((metadata.blocksMined + 1) % metadata.blockRewardHalvingInterval) 102 | }; 103 | } 104 | 105 | async getBalance(address) { 106 | return await this.db.balances.get(address) || 0; 107 | } 108 | 109 | async updateBalance(address, amount, txn = null) { 110 | const db = txn || this.db.balances; 111 | const currentBalance = await this.getBalance(address); 112 | await db.put(address, currentBalance + amount); 113 | } 114 | 115 | async getTransactionHistory(address, limit = 10) { 116 | const history = []; 117 | for await (const { value } of this.db.txHistory.getRange({ reverse: true })) { 118 | if (value.from === address || value.to === address) { 119 | history.push(value); 120 | if (history.length >= limit) break; 121 | } 122 | } 123 | return history; 124 | } 125 | 126 | async calculateCurrentReward() { 127 | const metadata = await this.getMetadata(); 128 | const halvings = Math.floor(metadata.blocksMined / metadata.blockRewardHalvingInterval); 129 | return metadata.miningReward / Math.pow(2, halvings); 130 | } 131 | 132 | async getCoinStats() { 133 | const metadata = await this.getMetadata(); 134 | return { 135 | currentSupply: metadata.currentSupply, 136 | maxSupply: metadata.maxSupply, 137 | remainingSupply: metadata.maxSupply - metadata.currentSupply, 138 | currentReward: await this.calculateCurrentReward(), 139 | blocksMined: metadata.blocksMined, 140 | blocksUntilHalving: metadata.blockRewardHalvingInterval - (metadata.blocksMined % metadata.blockRewardHalvingInterval) 141 | }; 142 | } 143 | 144 | async getAllBalances(opt = {}) { 145 | const balances = {}; 146 | for await (const { key, value } of this.db.balances.getRange(opt)) { 147 | balances[key] = value; 148 | } 149 | return balances; 150 | } 151 | } 152 | 153 | module.exports = { 154 | BlockchainDB, 155 | Transaction, 156 | }; -------------------------------------------------------------------------------- /src/utils/currency.js: -------------------------------------------------------------------------------- 1 | const db = require('./db.js'); 2 | 3 | module.exports = { 4 | format: (balance) => { 5 | return balance.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); 6 | }, 7 | subtract: (saldo, jumlah) => { 8 | saldo = parseInt(saldo); 9 | jumlah = parseInt(jumlah); 10 | 11 | if (saldo < jumlah) { 12 | return false; 13 | } 14 | 15 | return saldo - jumlah; 16 | }, 17 | 18 | add: (saldo, jumlah) => { 19 | return parseInt(saldo) + parseInt(jumlah); 20 | }, 21 | 22 | updateBalanceUser(userId, balance) { 23 | balance = parseInt(balance); 24 | if (!db.user.get(userId)) return false; 25 | db.update(db.user, userId, { balance }); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/utils/db.js: -------------------------------------------------------------------------------- 1 | const config = require('../../config.js'); 2 | const { default: axios } = require('axios') 3 | const path = require('path'); 4 | const { open } = require('lmdb'); 5 | const log = require('./log.js') 6 | const Block = require('./blockchain/block.js'); 7 | const moment = require('./moment.js'); 8 | 9 | class DatabaseManager { 10 | constructor() { 11 | this.user = null; 12 | this.group = null; 13 | this.bot = null; 14 | this.blockchain = { 15 | mine: null, 16 | chain: null, 17 | balances: null, 18 | metadata: null, 19 | pendingTx: null, 20 | txHistory: null 21 | }; 22 | } 23 | 24 | async init() { 25 | try { 26 | this.user = open({ 27 | path: path.join(config.STORAGE_DB, 'user'), 28 | }); 29 | 30 | this.group = open({ 31 | path: path.join(config.STORAGE_DB, 'group'), 32 | }); 33 | 34 | this.bot = open({ 35 | path: path.join(config.STORAGE_DB, 'bot'), 36 | }); 37 | 38 | // blockchain ------------------------ 39 | this.blockchain.mine = open({ 40 | path: path.join(config.STORAGE_DB, 'blockchain/mine'), 41 | }); 42 | this.blockchain.chain = open({ 43 | path: path.join(config.STORAGE_DB, 'blockchain/chain'), 44 | }); 45 | this.blockchain.balances = open({ 46 | path: path.join(config.STORAGE_DB, 'blockchain/balances'), 47 | }); 48 | this.blockchain.metadata = open({ 49 | path: path.join(config.STORAGE_DB, 'blockchain/metadata'), 50 | }); 51 | this.blockchain.pendingTx = open({ 52 | path: path.join(config.STORAGE_DB, 'blockchain/pendingtx'), 53 | }); 54 | this.blockchain.txHistory = open({ 55 | path: path.join(config.STORAGE_DB, 'blockchain/txhistory'), 56 | }); 57 | 58 | const metadata = await this.blockchain.metadata.get('blockchainInfo'); 59 | if (!metadata) { 60 | // Inisialisasi blockchain baru 61 | await this.blockchain.metadata.put('blockchainInfo', config.DATABASE_SCHEMA.blockchain); 62 | 63 | // Buat genesis block 64 | const genesisBlock = new Block(moment(), [], "0"); 65 | await this.blockchain.chain.put(0, genesisBlock); 66 | } 67 | // blockchain ------------------------ 68 | 69 | if(!this.bot.get('settings')) { 70 | const icon = await axios.get('https://i.pinimg.com/enabled_hi/1200x/6b/e2/b3/6be2b369fd5bca46e103af8f99263962.jpg', { responseType: 'arraybuffer' }).then(res => res.data) 71 | await this.bot.put('settings', { ...config.DATABASE_SCHEMA.bot, ...{ icon } }) 72 | } 73 | 74 | log.info(`Databases initialized successfully.`) 75 | } catch (error) { 76 | log.error(`Error initializing databases = ${error}.`) 77 | throw error; 78 | } 79 | } 80 | 81 | async update(db, key, value) { 82 | try { 83 | await db.put(key, { 84 | ...db.get(key), 85 | ...value, 86 | }); 87 | } catch (error) { 88 | console.error('Error updating database:', error); 89 | throw error; 90 | } 91 | } 92 | 93 | async close() { 94 | try { 95 | if (this.user) await this.user.close(); 96 | if (this.group) await this.group.close(); 97 | if (this.bot) await this.bot.close(); 98 | console.log('Databases closed successfully'); 99 | } catch (error) { 100 | console.error('Error closing databases:', error); 101 | throw error; 102 | } 103 | } 104 | } 105 | 106 | module.exports = new DatabaseManager(); -------------------------------------------------------------------------------- /src/utils/exp.js: -------------------------------------------------------------------------------- 1 | const db = require('./db.js'); 2 | const moment = require('./moment.js'); 3 | 4 | module.exports = { 5 | random: (min, max) => Math.floor(Math.random() * (max - min + 1)) + min, 6 | add: (id, amount) => { 7 | let user = db.user.get(id); 8 | if (!user) return false; 9 | db.update(db.user, id, { exp: parseInt(user.exp) + parseInt(amount), updated_at: moment() }); 10 | } 11 | } -------------------------------------------------------------------------------- /src/utils/games/blackjack.js: -------------------------------------------------------------------------------- 1 | /* 2 | #BlackJack Module 3 | 4 | Author : Ilsya 5 | Github : https://github.com/ilsyaa 6 | Website : https://ilsya.my.id 7 | */ 8 | 9 | const bjMap = new Map(); 10 | const suits = ['♠', '♣', '♥', '♦']; 11 | const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']; 12 | 13 | function createDeck() { 14 | const deck = []; 15 | for (const suit of suits) { 16 | for (const value of values) { 17 | deck.push({ suit, value }); 18 | } 19 | } 20 | return shuffle(deck); 21 | } 22 | 23 | function shuffle(array) { 24 | for (let i = array.length - 1; i > 0; i--) { 25 | const j = Math.floor(Math.random() * (i + 1)); 26 | [array[i], array[j]] = [array[j], array[i]]; 27 | } 28 | return array; 29 | } 30 | 31 | function getCardValue(card) { 32 | if (['J', 'Q', 'K'].includes(card.value)) return 10; 33 | if (card.value === 'A') return 11; 34 | return parseInt(card.value); 35 | } 36 | 37 | function calculateHandValue(hand) { 38 | let value = 0; 39 | let aces = 0; 40 | 41 | // Hitung semua kartu kecuali Ace 42 | for (const card of hand) { 43 | if (card.value === 'A') { 44 | aces++; 45 | } else { 46 | value += getCardValue(card); 47 | } 48 | } 49 | 50 | // Tambahkan nilai untuk setiap Ace 51 | for (let i = 0; i < aces; i++) { 52 | if (value + 11 <= 21) { 53 | value += 11; 54 | } else { 55 | value += 1; 56 | } 57 | } 58 | 59 | return value; 60 | } 61 | 62 | function formatCard(card) { 63 | return `${card.value}${card.suit}`; 64 | } 65 | 66 | function formatHand(hand) { 67 | return hand.map(formatCard).join(' '); 68 | } 69 | 70 | async function addReactions(sock, key, status) { 71 | if (status === 'hit') { 72 | await sock.sendMessage(key.remoteJid, { 73 | react: { 74 | text: "👊", 75 | key: key 76 | } 77 | }); 78 | } 79 | 80 | if (status === 'stand') { 81 | await sock.sendMessage(key.remoteJid, { 82 | react: { 83 | text: "✋", 84 | key: key 85 | } 86 | }); 87 | } 88 | } 89 | 90 | module.exports = { 91 | bjMap, 92 | createDeck, 93 | shuffle, 94 | calculateHandValue, 95 | formatCard, 96 | formatHand, 97 | addReactions, 98 | getCardValue 99 | } -------------------------------------------------------------------------------- /src/utils/games/tictactoe.js: -------------------------------------------------------------------------------- 1 | const ticMap = new Map(); 2 | const emoji = { 3 | X: '❌', 4 | O: '⭕', 5 | 1: '1️⃣', 6 | 2: '2️⃣', 7 | 3: '3️⃣', 8 | 4: '4️⃣', 9 | 5: '5️⃣', 10 | 6: '6️⃣', 11 | 7: '7️⃣', 12 | 8: '8️⃣', 13 | 9: '9️⃣' 14 | }; 15 | 16 | module.exports = { 17 | ticMap, 18 | emoji, 19 | createGame(chatId, player1, player2, isBotGame = false, bet = 0) { 20 | const gameState = { 21 | board: [1, 2, 3, 4, 5, 6, 7, 8, 9], 22 | currentPlayer: player1, 23 | players: { 24 | X: player1, 25 | O: player2 26 | }, 27 | status: isBotGame ? 'playing' : 'waiting', 28 | bet, 29 | isBotGame: isBotGame 30 | }; 31 | ticMap.set(chatId, gameState); 32 | return this.getGameState(chatId); 33 | }, 34 | 35 | getGameState(chatId) { 36 | const game = ticMap.get(chatId); 37 | let boardDisplay = this.getBoardDisplay(game.board); 38 | return { 39 | bet: game.bet, 40 | board: boardDisplay, 41 | currentPlayer: game.currentPlayer, 42 | players: game.players, 43 | status: game.status, 44 | isBotGame: game.isBotGame 45 | }; 46 | }, 47 | getBoardDisplay(board) { 48 | let display = ''; 49 | for (let i = 0; i < 9; i += 3) { 50 | display += `${this.getEmoji(board[i])}${this.getEmoji(board[i + 1])}${this.getEmoji(board[i + 2])}\n`; 51 | } 52 | return display.trim(); 53 | }, 54 | 55 | getEmoji(value) { 56 | return this.emoji[value] || value; 57 | }, 58 | 59 | checkWin(board) { 60 | const winConditions = [ 61 | [0, 1, 2], [3, 4, 5], [6, 7, 8], // Horizontal 62 | [0, 3, 6], [1, 4, 7], [2, 5, 8], // Vertical 63 | [0, 4, 8], [2, 4, 6] // Diagonal 64 | ]; 65 | 66 | return winConditions.some(condition => { 67 | const [a, b, c] = condition; 68 | return board[a] === board[b] && board[b] === board[c]; 69 | }); 70 | }, 71 | 72 | endGame(chatId) { 73 | return ticMap.delete(chatId); 74 | }, 75 | 76 | AIMove(chatId) { 77 | const game = ticMap.get(chatId); 78 | if (!game || !game.isBotGame) return null; 79 | 80 | // Dapatkan posisi kosong 81 | const emptyPositions = game.board 82 | .map((cell, index) => typeof cell === 'number' ? index + 1 : null) 83 | .filter(pos => pos !== null); 84 | 85 | // Strategi bot: 86 | // 1. Cek kemungkinan menang 87 | // 2. Blok kemungkinan lawan menang 88 | // 3. Ambil tengah jika kosong 89 | // 4. Ambil sudut kosong 90 | // 5. Ambil posisi random yang tersedia 91 | 92 | // Coba setiap posisi kosong untuk mencari gerakan menang 93 | for (let pos of emptyPositions) { 94 | const testBoard = [...game.board]; 95 | testBoard[pos - 1] = 'O'; 96 | if (this.checkWin(testBoard)) { 97 | return this.makeMove(chatId, game.players.O, pos); 98 | } 99 | } 100 | 101 | // Cek dan blok kemungkinan menang lawan 102 | for (let pos of emptyPositions) { 103 | const testBoard = [...game.board]; 104 | testBoard[pos - 1] = 'X'; 105 | if (this.checkWin(testBoard)) { 106 | return this.makeMove(chatId, game.players.O, pos); 107 | } 108 | } 109 | 110 | // Ambil posisi tengah jika kosong 111 | if (emptyPositions.includes(5)) { 112 | return this.makeMove(chatId, game.players.O, 5); 113 | } 114 | 115 | // Ambil sudut kosong 116 | const corners = [1, 3, 7, 9].filter(corner => emptyPositions.includes(corner)); 117 | if (corners.length > 0) { 118 | const corner = corners[Math.floor(Math.random() * corners.length)]; 119 | return this.makeMove(chatId, game.players.O, corner); 120 | } 121 | 122 | // Ambil posisi random 123 | const randomPos = emptyPositions[Math.floor(Math.random() * emptyPositions.length)]; 124 | return this.makeMove(chatId, game.players.O, randomPos); 125 | }, 126 | 127 | makeMove(chatId, player, position, msg) { 128 | const game = ticMap.get(chatId); 129 | if (player !== game.currentPlayer) return { error: msg.notYourTurn }; 130 | if (position < 1 || position > 9) return { error: msg.invalidPosition }; 131 | 132 | const index = position - 1; 133 | if (typeof game.board[index] !== 'number') return { error: msg.positionAlreadyFilled }; 134 | 135 | // Menentukan simbol pemain 136 | const symbol = game.players.X === player ? 'X' : 'O'; 137 | game.board[index] = symbol; 138 | 139 | // Cek kondisi menang 140 | if (this.checkWin(game.board)) { 141 | game.status = 'won'; 142 | return { 143 | ...this.getGameState(chatId), 144 | winner: player 145 | }; 146 | } 147 | 148 | // Cek kondisi seri 149 | if (!game.board.some(cell => typeof cell === 'number')) { 150 | game.status = 'draw'; 151 | return this.getGameState(chatId); 152 | } 153 | 154 | // Ganti giliran 155 | game.currentPlayer = (game.currentPlayer === game.players.X) ? game.players.O : game.players.X; 156 | return this.getGameState(chatId); 157 | } 158 | 159 | } -------------------------------------------------------------------------------- /src/utils/loadCommands.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | const commandsDir = path.join(__dirname, '../command') 4 | const commands = new Map(); 5 | const menuByLabel = new Map() 6 | const log = require("./log.js") 7 | 8 | const loadFile = (filePath) => { 9 | try { 10 | if(filePath.endsWith('.js')) { 11 | const file = require(filePath); 12 | const name = file.name.toLowerCase().replace(/\s/g, ""); 13 | if (!commands.has(name)) { 14 | commands.set(name, file) 15 | } else { 16 | log.error(`duplication name ${name}.`) 17 | } 18 | } 19 | return false 20 | } catch (e) { 21 | log.error(e) 22 | } 23 | } 24 | 25 | const exploreFolder = (dir) => { 26 | fs.readdirSync(dir).forEach(dirOrFile => { 27 | const dirOrFilePath = path.join(dir, dirOrFile); 28 | if (fs.statSync(dirOrFilePath).isDirectory()) { 29 | exploreFolder(dirOrFilePath); 30 | } else { 31 | loadFile(dirOrFilePath); 32 | } 33 | }); 34 | } 35 | 36 | const loadCommands = async() => { 37 | exploreFolder(commandsDir) 38 | commands.forEach(val => { 39 | let label = val.menu?.label 40 | if(label){ 41 | if(!menuByLabel.has(label)){ 42 | menuByLabel.set(label, []) 43 | } 44 | menuByLabel.get(label).push({ 45 | cmd : val.cmd, 46 | example : val.menu.example 47 | }) 48 | } 49 | }) 50 | log.info(`Loaded ${commands.size} commands.`) 51 | } 52 | 53 | module.exports = { 54 | loadCommands, 55 | commands, 56 | menuByLabel 57 | } -------------------------------------------------------------------------------- /src/utils/log.js: -------------------------------------------------------------------------------- 1 | const Logger = require("@ptkdev/logger") 2 | const log = new Logger() 3 | 4 | module.exports = log -------------------------------------------------------------------------------- /src/utils/moment.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment-timezone'); 2 | moment.tz.setDefault(process.env.TZ || 'Asia/Jakarta'); 3 | 4 | module.exports = moment; -------------------------------------------------------------------------------- /src/utils/ruhend-scrapper/tiktok.js: -------------------------------------------------------------------------------- 1 | function _0x584d(){const _0x1349ed=['JIFbQ','wmplay','xt/javascr','/api/','NAyOF','yOtjo','qhSHa','floor','in64;\x20x64)','ipt,\x20*/*;\x20','comment_co','521500labhwU','play_count','hdplay','json','BqzTM','4540905AHUODD','ZIFPj','TrUNQ','ring','1605300FiLkWZ','random','=\x22104\x22','443','\x20Chrome\x22;v','QFwGW','WStKu','NOrPb','https://ww','avatar','n/x-www-fo','data','unique_id','nickname','sLjBn','et=UTF-8','trim','collect_co','ded;\x20chars','\x22\x20Not\x20A;Br','1380395mNXPwH','\x22Chromium\x22','digg_count','203110MoZFdf',';v=\x22104\x22,\x20','q=0.01','rm-urlenco','node-fetch','author','ke\x20Gecko)\x20','(KHTML,\x20li','n/json,\x20te','Chrome/104','\x20(Windows\x20','cover','.0.0.0\x20Saf','gone\x20wrong','play','mzSrR','unt','POST','exports','15pMeWyQ','\x22,\x20\x22Google','title','64erQBiK','ari/537.36','region','\x20AppleWebK','NT\x2010.0;\x20W','toLocaleDa','Chrome/5.0','teString','w.tikwm.co','applicatio','678407ZLHshT','xKIJv','something\x20','Wttcg','toLocaleSt','music_info','1015372hPFDlJ','pUUZw','gbXHQ','it/537.36\x20','DQqla','and\x22;v=\x2299','iLSZH','create_tim'];_0x584d=function(){return _0x1349ed;};return _0x584d();}const _0x4e51ca=_0x18c6;(function(_0x21896a,_0x2aad08){const _0x33554d=_0x18c6,_0x2c2979=_0x21896a();while(!![]){try{const _0x35820d=parseInt(_0x33554d(0x11b))/(0x7*0x12a+0xab*-0x2f+-0x10*-0x174)+-parseInt(_0x33554d(0x154))/(0xea3+-0x16*-0x35+-0x665*0x3)*(parseInt(_0x33554d(0x167))/(-0x581*0x1+0xa*0x36d+-0x236*0xd))+-parseInt(_0x33554d(0x121))/(-0x12bb+-0x53*-0x4f+0x24a*-0x3)+parseInt(_0x33554d(0x151))/(-0x17b*0x3+0x1*0x152b+-0x1*0x10b5)+parseInt(_0x33554d(0x13d))/(0x1*0x12e0+-0xc64+-0x676)+parseInt(_0x33554d(0x134))/(0x1*0xcd6+-0xc40+0x8f*-0x1)*(-parseInt(_0x33554d(0x16a))/(-0x67f*0x2+-0x4a7*0x3+0x1afb))+parseInt(_0x33554d(0x139))/(-0xbf1+-0x72*-0x26+-0x4f2);if(_0x35820d===_0x2aad08)break;else _0x2c2979['push'](_0x2c2979['shift']());}catch(_0x4f431d){_0x2c2979['push'](_0x2c2979['shift']());}}}(_0x584d,-0x9bdb5+0xa8232+0x4dcc6),module[_0x4e51ca(0x166)]={'ttdl':ttdl});function generateRandomIP(){const _0x2584e9=_0x4e51ca,_0x538b65={'iLSZH':function(_0x4f25bc){return _0x4f25bc();}},_0x1cf1ff=()=>Math[_0x2584e9(0x130)](Math[_0x2584e9(0x13e)]()*(-0x59*0x3+0x1c93+-0x1a8a));return _0x538b65[_0x2584e9(0x127)](_0x1cf1ff)+'.'+_0x538b65[_0x2584e9(0x127)](_0x1cf1ff)+'.'+_0x538b65[_0x2584e9(0x127)](_0x1cf1ff)+'.'+_0x538b65[_0x2584e9(0x127)](_0x1cf1ff);}const fetch=require(_0x4e51ca(0x158));function _0x18c6(_0xbaf489,_0x17998f){const _0x545597=_0x584d();return _0x18c6=function(_0x129853,_0x4960f2){_0x129853=_0x129853-(-0x1db9*-0x1+-0x1*-0x1835+-0x34d3);let _0x131949=_0x545597[_0x129853];return _0x131949;},_0x18c6(_0xbaf489,_0x17998f);}async function ttdl(_0x27536d){const _0x4d9e27=_0x4e51ca,_0x2c21a3={'WStKu':_0x4d9e27(0x145)+_0x4d9e27(0x172)+'m','NAyOF':function(_0x52273c,_0x32e0c9,_0x1fd63c){return _0x52273c(_0x32e0c9,_0x1fd63c);},'ZIFPj':function(_0x1839ae,_0x59582e){return _0x1839ae+_0x59582e;},'DQqla':_0x4d9e27(0x12c),'sLjBn':_0x4d9e27(0x165),'pUUZw':_0x4d9e27(0x173)+_0x4d9e27(0x15c)+_0x4d9e27(0x12b)+_0x4d9e27(0x132)+_0x4d9e27(0x156),'mzSrR':_0x4d9e27(0x173)+_0x4d9e27(0x147)+_0x4d9e27(0x157)+_0x4d9e27(0x14f)+_0x4d9e27(0x14c),'qhSHa':function(_0x1930ac){return _0x1930ac();},'JIFbQ':_0x4d9e27(0x140),'BqzTM':_0x4d9e27(0x152)+_0x4d9e27(0x155)+_0x4d9e27(0x150)+_0x4d9e27(0x126)+_0x4d9e27(0x168)+_0x4d9e27(0x141)+_0x4d9e27(0x13f),'yOtjo':_0x4d9e27(0x170)+_0x4d9e27(0x15e)+_0x4d9e27(0x16e)+_0x4d9e27(0x131)+_0x4d9e27(0x16d)+_0x4d9e27(0x124)+_0x4d9e27(0x15b)+_0x4d9e27(0x15a)+_0x4d9e27(0x15d)+_0x4d9e27(0x160)+_0x4d9e27(0x16b),'gbXHQ':function(_0x5099ea,_0x467e8d){return _0x5099ea+_0x467e8d;},'TrUNQ':function(_0x44a21b,_0x2ddee4){return _0x44a21b*_0x2ddee4;},'NOrPb':function(_0x5b51d0,_0xfdae43){return _0x5b51d0+_0xfdae43;},'QFwGW':function(_0x3bdb16,_0x5180ff){return _0x3bdb16+_0x5180ff;},'Wttcg':function(_0x1a2944,_0x2d29fd){return _0x1a2944+_0x2d29fd;},'xKIJv':_0x4d9e27(0x11d)+_0x4d9e27(0x161)};try{let _0x2d863e=_0x2c21a3[_0x4d9e27(0x143)],_0x5a4f16=await _0x2c21a3[_0x4d9e27(0x12d)](fetch,_0x2c21a3[_0x4d9e27(0x13a)](_0x2d863e,_0x2c21a3[_0x4d9e27(0x125)]),{'method':_0x2c21a3[_0x4d9e27(0x14b)],'headers':{'Accept':_0x2c21a3[_0x4d9e27(0x122)],'Content-Type':_0x2c21a3[_0x4d9e27(0x163)],'X-Forwarded-For':_0x2c21a3[_0x4d9e27(0x12f)](generateRandomIP),'Custom-Port':_0x2c21a3[_0x4d9e27(0x129)],'Sec-CH-UA':_0x2c21a3[_0x4d9e27(0x138)],'User-Agent':_0x2c21a3[_0x4d9e27(0x12e)]},'body':new URLSearchParams({'url':_0x27536d,'count':0xc,'cursor':0x0,'web':0x1,'hd':0x1})}),_0x387f79=await _0x5a4f16[_0x4d9e27(0x137)](),_0x51677e=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x16c)],_0x5cc5a7=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x169)],_0x51973a=_0x2c21a3[_0x4d9e27(0x123)](_0x2d863e,_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x159)][_0x4d9e27(0x146)]),_0x232ddf=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x159)][_0x4d9e27(0x14a)],_0x590188=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x159)][_0x4d9e27(0x149)],_0x56485d=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x133)+_0x4d9e27(0x164)][_0x4d9e27(0x11f)+_0x4d9e27(0x13c)](),_0x1b030e=_0x2c21a3[_0x4d9e27(0x123)](_0x2d863e,_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x15f)]),_0x38df6f=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x135)][_0x4d9e27(0x11f)+_0x4d9e27(0x13c)](),_0x764898=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x153)][_0x4d9e27(0x11f)+_0x4d9e27(0x13c)](),_0x25ee30=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x14e)+_0x4d9e27(0x164)][_0x4d9e27(0x11f)+_0x4d9e27(0x13c)](),_0x44a7e4=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x128)+'e'],_0x1c0e80=new Date(_0x2c21a3[_0x4d9e27(0x13b)](_0x44a7e4,-0x1213+0x11f0+0x40b)),_0x5b215a=_0x1c0e80[_0x4d9e27(0x16f)+_0x4d9e27(0x171)](),_0x4da2f7=_0x5b215a[_0x4d9e27(0x14d)](),_0x3a8f9b=_0x2c21a3[_0x4d9e27(0x144)](_0x2d863e,_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x162)]),_0x49282f=_0x2c21a3[_0x4d9e27(0x142)](_0x2d863e,_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x12a)]),_0x52b0e6=_0x2c21a3[_0x4d9e27(0x11e)](_0x2d863e,_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x136)]),_0x27bc0d=_0x387f79[_0x4d9e27(0x148)][_0x4d9e27(0x120)][_0x4d9e27(0x162)],_0x54c7a7='';return{'region':_0x51677e,'title':_0x5cc5a7,'avatar':_0x51973a,'author':_0x232ddf,'username':_0x590188,'comment':_0x56485d,'views':_0x38df6f,'cover':_0x1b030e,'like':_0x764898,'bookmark':_0x25ee30,'published':_0x4da2f7,'video':_0x3a8f9b,'video_wm':_0x49282f,'video_hd':_0x52b0e6,'music':_0x27bc0d,'duration':_0x54c7a7};}catch(_0x411730){throw _0x2c21a3[_0x4d9e27(0x11c)];}} -------------------------------------------------------------------------------- /src/utils/scraper.js: -------------------------------------------------------------------------------- 1 | const { ttdl } = require('./ruhend-scrapper/tiktok.js'); 2 | const { fbdl } = require('./ruhend-scrapper/facebook.js'); 3 | module.exports = { ttdl, fbdl } -------------------------------------------------------------------------------- /src/utils/stickerMaker.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Crypto = require("crypto") 3 | const ff = require('fluent-ffmpeg') 4 | const webp = require("node-webpmux") 5 | const path = require("path") 6 | const config = require("../../config"); 7 | 8 | function tmpdir() { 9 | return config.STORAGE_PATH+'/temp' 10 | } 11 | 12 | async function imageToWebp(media) { 13 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 14 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.jpg`) 15 | fs.writeFileSync(tmpFileIn, media) 16 | await new Promise((resolve, reject) => { 17 | ff(tmpFileIn) 18 | .on("error", reject) 19 | .on("end", () => resolve(true)) 20 | .addOutputOptions([ 21 | "-vcodec", 22 | "libwebp", 23 | "-vf", 24 | `scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15, 25 | crop=min(iw\\,ih):min(iw\\,ih), scale=320:320, 26 | pad=320:320:-1:-1:color=white@0.0, 27 | split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse` 28 | ]) 29 | .toFormat("webp") 30 | .save(tmpFileOut) 31 | }) 32 | const buff = fs.readFileSync(tmpFileOut) 33 | fs.unlinkSync(tmpFileOut) 34 | fs.unlinkSync(tmpFileIn) 35 | return buff 36 | } 37 | 38 | async function videoToWebp(media) { 39 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 40 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.mp4`) 41 | fs.writeFileSync(tmpFileIn, media) 42 | await new Promise((resolve, reject) => { 43 | ff(tmpFileIn) 44 | .on("error", reject) 45 | .on("end", () => resolve(true)) 46 | .addOutputOptions([ 47 | "-vcodec", 48 | "libwebp", 49 | "-vf", 50 | "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15, crop=min(iw\\,ih):min(iw\\,ih), scale=320:320, pad=320:320:-1:-1:color=white@0.0, split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse", 51 | "-loop", 52 | "0", 53 | "-ss", 54 | "00:00:00", 55 | "-t", 56 | "00:00:05", 57 | "-preset", 58 | "default", 59 | "-an", 60 | "-vsync", 61 | "0" 62 | ]) 63 | .toFormat("webp") 64 | .save(tmpFileOut) 65 | }) 66 | const buff = fs.readFileSync(tmpFileOut) 67 | fs.unlinkSync(tmpFileOut) 68 | fs.unlinkSync(tmpFileIn) 69 | return buff 70 | } 71 | 72 | /** 73 | * Convert image to webp, adding meme text on top and bottom 74 | * @param {Buffer} media The image buffer 75 | * @param {string} textTop The text to add on top 76 | * @param {string} textBottom The text to add on bottom 77 | * @return {Promise} The webp buffer 78 | */ 79 | 80 | async function webpToVideo(media) { 81 | const tmpFileIn = media; 82 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.mp4`); 83 | 84 | await new Promise((resolve, reject) => { 85 | ff(tmpFileIn) 86 | .on('error', reject) 87 | .on('end', () => resolve(true)) 88 | .addOutputOptions([ 89 | '-vf', 90 | 'scale=320:320', // menyesuaikan ukuran, bisa diubah sesuai kebutuhan 91 | '-r', 92 | '15', // fps, bisa diubah sesuai kebutuhan 93 | ]) 94 | .toFormat('mp4') 95 | .save(tmpFileOut); 96 | }); 97 | 98 | const buff = fs.readFileSync(tmpFileOut); 99 | fs.unlinkSync(tmpFileOut); 100 | fs.unlinkSync(tmpFileIn); 101 | 102 | return buff; 103 | } 104 | 105 | async function writeExifImg(media, metadata) { 106 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 107 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 108 | fs.writeFileSync(tmpFileIn, media) 109 | if (metadata.packname || metadata.author) { 110 | const img = new webp.Image() 111 | const json = { "sticker-pack-id": `https://github.com/ilsyaa`, "sticker-pack-name": metadata.packname, "sticker-pack-publisher": metadata.author, "emojis": metadata.categories ? metadata.categories : [""] } 112 | const exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]) 113 | const jsonBuff = Buffer.from(JSON.stringify(json), "utf-8") 114 | const exif = Buffer.concat([exifAttr, jsonBuff]) 115 | exif.writeUIntLE(jsonBuff.length, 14, 4) 116 | await img.load(tmpFileIn) 117 | fs.unlinkSync(tmpFileIn) 118 | img.exif = exif 119 | await img.save(tmpFileOut) 120 | const buff = fs.readFileSync(tmpFileOut) 121 | fs.unlinkSync(tmpFileOut) 122 | return buff 123 | } 124 | } 125 | 126 | async function writeExifVid(buffer, metadata) { 127 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 128 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 129 | fs.writeFileSync(tmpFileIn, buffer) 130 | if (metadata.packname || metadata.author) { 131 | const img = new webp.Image() 132 | const json = { "sticker-pack-id": `https://velixs.com`, "sticker-pack-name": metadata.packname, "sticker-pack-publisher": metadata.author, "emojis": metadata.categories ? metadata.categories : [""] } 133 | const exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]) 134 | const jsonBuff = Buffer.from(JSON.stringify(json), "utf-8") 135 | const exif = Buffer.concat([exifAttr, jsonBuff]) 136 | 137 | exif.writeUIntLE(jsonBuff.length, 14, 4) 138 | await img.load(tmpFileIn) 139 | fs.unlinkSync(tmpFileIn) 140 | img.exif = exif 141 | await img.save(tmpFileOut) 142 | const buff = fs.readFileSync(tmpFileOut) 143 | fs.unlinkSync(tmpFileOut) 144 | return buff 145 | } 146 | } 147 | 148 | module.exports = { imageToWebp, videoToWebp, webpToVideo ,writeExifImg, writeExifVid } -------------------------------------------------------------------------------- /src/utils/timer2.js: -------------------------------------------------------------------------------- 1 | const moment = require('./moment.js'); 2 | 3 | module.exports = time2 = () => { 4 | const time2 = moment().tz('Asia/Jakarta').format('HH:mm:ss') 5 | if (time2 < "23:59:00") { 6 | var ucapanWaktu = 'Malam 🏙️' 7 | } 8 | if (time2 < "19:00:00") { 9 | var ucapanWaktu = 'Petang 🌆' 10 | } 11 | if (time2 < "18:00:00") { 12 | var ucapanWaktu = 'Sore 🌇' 13 | } 14 | if (time2 < "15:00:00") { 15 | var ucapanWaktu = 'Siang 🌤️' 16 | } 17 | if (time2 < "10:00:00") { 18 | var ucapanWaktu = 'Pagi 🌄' 19 | } 20 | if (time2 < "05:00:00") { 21 | var ucapanWaktu = 'Subuh 🌆' 22 | } 23 | if (time2 < "03:00:00") { 24 | var ucapanWaktu = 'Tengah Malam 🌃' 25 | } 26 | 27 | return ucapanWaktu 28 | } -------------------------------------------------------------------------------- /src/utils/uploader.js: -------------------------------------------------------------------------------- 1 | const { FormData, Blob } = require('formdata-node'); 2 | const { fromBuffer } = require('file-type'); 3 | const axios = require('axios'); 4 | 5 | const quax = async (buffer) => { 6 | const { ext, mime } = await fromBuffer(buffer) 7 | const form = new FormData() 8 | const blob = new Blob([buffer], { type: mime }) 9 | form.append('files[]', blob, 'tmp.' + ext) 10 | const { data } = await axios.post("https://qu.ax/upload.php", form, { 11 | headers: { 12 | "Content-Type": "multipart/form-data", 13 | }, 14 | }) 15 | return data.files[0].url; 16 | } 17 | 18 | module.exports = { 19 | quax 20 | } -------------------------------------------------------------------------------- /src/utils/validate-url.js: -------------------------------------------------------------------------------- 1 | const validateUrl = (urlString) => { 2 | try { 3 | new URL(urlString); 4 | return true; // URL valid 5 | } catch (e) { 6 | return false; // URL tidak valid 7 | } 8 | }; 9 | 10 | module.exports = validateUrl -------------------------------------------------------------------------------- /storage/bug.pdf: -------------------------------------------------------------------------------- 1 | helloworld -------------------------------------------------------------------------------- /storage/databases/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /storage/media/coin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilsyaa/lazy-whatsapp-bot/7fdc0feee184f3b6c3268db2b1d287b46e67c328/storage/media/coin.jpg -------------------------------------------------------------------------------- /storage/media/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilsyaa/lazy-whatsapp-bot/7fdc0feee184f3b6c3268db2b1d287b46e67c328/storage/media/test.png -------------------------------------------------------------------------------- /storage/session/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /storage/temp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const currency = require('./src/utils/currency.js'); 2 | 3 | console.log(currency.subtract(10, 9)) 4 | console.log(currency.subtract(10, 10)) 5 | console.log(currency.subtract(10, 11)) 6 | 7 | if(currency.subtract(10, 9)) { 8 | console.log('Uang Cukup') 9 | } else { 10 | console.log('Uang Kurang') 11 | } --------------------------------------------------------------------------------