├── .eslintrc.js ├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── ask.md │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── greetings.yml ├── .gitignore ├── LICENSE ├── README.md ├── config.json ├── database ├── bot │ ├── banned.json │ ├── mute.json │ ├── premium.json │ ├── registered.json │ ├── setting.json │ └── sticker.json ├── group │ ├── antilink.json │ ├── antinsfw.json │ ├── autosticker.json │ ├── badwords.json │ ├── leveling.json │ ├── nsfw.json │ └── welcome.json └── user │ ├── afk.json │ ├── daily.json │ ├── level.json │ ├── limit.json │ └── reminder.json ├── function ├── afk.js ├── daily.js ├── index.js ├── level.js ├── limit.js ├── loader.js ├── premium.js ├── quizizz.js ├── register.js └── reminder.js ├── index.js ├── lib ├── downloader.js ├── index.js └── weeaboo.js ├── message ├── index.js └── text │ └── lang │ ├── eng.js │ ├── ind.js │ └── index.js ├── package-lock.json ├── package.json └── tools ├── fetcher.js └── index.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'env': { 3 | 'es2021': true, 4 | 'node': true 5 | }, 6 | 'extends': 'eslint:recommended', 7 | 'parserOptions': { 8 | 'ecmaVersion': 12 9 | }, 10 | 'rules': { 11 | 'no-empty': 'warn', 12 | 'no-extra-semi': 'warn', 13 | 'no-unexpected-multiline': 'warn', 14 | 'default-case': 'error', 15 | 'default-case-last': 'error', 16 | 'no-alert': 'warn', 17 | 'no-empty-function': 'warn', 18 | 'no-invalid-this': 'warn', 19 | 'no-useless-catch': 'warn', 20 | 'require-await': 'error', 21 | 'quotes': ['warn', 'single'] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at slavyan@secret.fyi. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: slavyandesu 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ask.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask anything 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Question** 11 | What would you like to ask? 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/first-interaction@v1 10 | with: 11 | repo-token: ${{ secrets.GITHUB_TOKEN }} 12 | issue-message: 'Hello! Thanks for submiting the issue, we will respond to you ASAP.' 13 | pr-message: 'Hello! Thank you for contributing to this repo, we will review your commits ASAP.' 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.data.json 3 | logs 4 | .node-persist 5 | _IGNORE_* 6 | temp 7 | **.data.json 8 | **.node-persist** 9 | **_IGNORE_** -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SlavyanDesu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | BocchiBot 3 | 4 | # **BocchiBot** 5 | 6 | > BocchiBot is a multipurpose WhatsApp bot using wa-automate-nodejs library! 7 | > 8 | > 9 | 10 |

Made with ❤️ by

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | Requirements • 26 | Installation • 27 | Features • 28 | Thanks to • 29 | License 30 |
31 | 32 | # Requirements 33 | * [Node.js](https://nodejs.org/en/) 34 | * [Git](https://git-scm.com/downloads) 35 | * [FFmpeg](https://www.gyan.dev/ffmpeg/builds/) 36 | * [Tesseract](https://github.com/tesseract-ocr/tesseract) 37 | 38 | # Installation 39 | ## 📝 Cloning the repo 40 | ```cmd 41 | > git clone https://github.com/SlavyanDesu/BocchiBot.git 42 | > cd BocchiBot 43 | ``` 44 | 45 | ## ✍️ Editing the file 46 | Edit the required value in `config.json`. 47 | ```json 48 | { 49 | "ownerBot": "62812xxxxxxxx@c.us", 50 | "prefix": ".", 51 | "nao": "SAUCENAO-API-KEY", 52 | "openAiKey": "OPENAI-API-KEY", 53 | "authorStick": "@SlavyanDesu", 54 | "packStick": "BocchiBot" 55 | } 56 | ``` 57 | 58 | `ownerBot`: your WhatsApp number. 59 | `prefix`: bot's prefix. 60 | `nao`: SauceNAO API key. You can get it [here](https://saucenao.com/user.php) by creating an account. 61 | `openAiKey`: OpenAI API key. You can get it [here](https://platform.openai.com/account/api-keys) by creating an account. 62 | `authorStick`: name of the author sticker pack. 63 | `packStick`: name of the sticker pack. 64 | 65 | ## 🗣️ Changing Language 66 | Replace all of `eng` to `ind` for Bahasa Indonesia. 67 | 68 | ## 🛠️ Installing the FFmpeg 69 | * Download one of the available versions of FFmpeg by clicking [this link](https://www.gyan.dev/ffmpeg/builds/). 70 | * Extract the file to `C:\` path. 71 | * Rename the extracted folder to `ffmpeg`. 72 | * Run Command Prompt as Administrator. 73 | * Run this command: 74 | ```cmd 75 | > setx /m PATH "C:\ffmpeg\bin;%PATH%" 76 | ``` 77 | It will give us a callback like `SUCCESS: specified value was saved`. 78 | * Now that you've FFmpeg installed, verify that it's working by running this command to see version number: 79 | ```cmd 80 | > ffmpeg -version 81 | ``` 82 | 83 | ## 🛠️ Installing the Tesserract 84 | * Download the Tesseract program [here](https://s.id/vftesseract). 85 | * Run the Tesseract program with run As Administrator. 86 | * Make sure the Tesseract installation is in the `C:\` folder 87 | * Run Command Prompt as Administrator. 88 | * Run this command: 89 | ```cmd 90 | > setx /m PATH "C:\Tesseract-OCR;%PATH%" 91 | ``` 92 | It will give us a callback like `SUCCESS: specified value was saved`. 93 | * Now that you've Tesseract installed, verify that it's working by running this command to see version number: 94 | ```cmd 95 | > tesseract -version 96 | ``` 97 | 98 | ## 🔍 Installing the dependencies 99 | ```cmd 100 | > npm install 101 | ``` 102 | 103 | ## 🆗 Running the bot 104 | Regular node: 105 | ```cmd 106 | > npm start 107 | ``` 108 | 109 | PM2: 110 | ```cmd 111 | > pm2 start index.js -i max 112 | > pm2 monit 113 | ``` 114 | 115 | After that scan the QR code using your WhatsApp in your phone. 116 | 117 | # Features 118 | Type `.help` to your bot number to see the list of commands. 119 | 120 | # Thanks to 121 | * [`open-wa/wa-automate-nodejs`](https://github.com/open-wa/wa-automate-nodejs) 122 | * [`YogaSakti/imageToSticker`](https://github.com/YogaSakti/imageToSticker) 123 | * [`uukina`](https://github.com/uukina) 124 | * [`VideFrelan`](https://github.com/VideFrelan) 125 | * [`Pahri123`](https://github.com/Pahri123) 126 | * [`LeviathanH`](https://github.com/LeviathanH) 127 | * [`ferlitopym`](https://github.com/ferlitopym) 128 | * [`AlvioAdjiJanuar`](https://github.com/Piyoxz) 129 | * [`VirusLauncher`](https://github.com/VirusLauncher) 130 | * [`Sansekai`](https://github.com/Sansekai) 131 | * [`Baguettou`](https://github.com/Baguettou) 132 | * [`HAFizh-15`](https://github.com/HAFizh-15) 133 | * [`TheSploit`](https://github.com/TheSploit) 134 | * [`rashidsiregar28`](https://github.com/rashidsiregar28) 135 | * [`irham01`](https://github.com/irham01) 136 | * [`hardiantojek93`](https://github.com/hardiantojek93) 137 | * [`gamingrkp`](https://github.com/gamingrkp) 138 | 139 | # License 140 | **BocchiBot** © [SlavyanDesu](https://github.com/SlavyanDesu), released under the MIT License. 141 | Authored and maintained by SlavyanDesu. 142 | 143 |
144 | 145 |
146 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ownerBot": "62xxxxxxx@c.us", 3 | "prefix": ".", 4 | "nao": "api-key", 5 | "openAiKey": "api-key", 6 | "authorStick": "@SlavyanDesu", 7 | "packStick": "BocchiBot" 8 | } 9 | -------------------------------------------------------------------------------- /database/bot/banned.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/bot/mute.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/bot/premium.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/bot/registered.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/bot/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "memberLimit": "1", 3 | "groupLimit": "10" 4 | } -------------------------------------------------------------------------------- /database/bot/sticker.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/antilink.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/antinsfw.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/autosticker.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/badwords.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/leveling.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/nsfw.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/group/welcome.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/user/afk.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/user/daily.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/user/level.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/user/limit.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/user/reminder.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /function/afk.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | /** 4 | * Add AFK user. 5 | * @param {string} userId 6 | * @param {string} time 7 | * @param {string} reason 8 | * @param {object} _dir 9 | */ 10 | const addAfkUser = (userId, time, reason, _dir) => { 11 | const obj = { id: userId, time: time, reason: reason } 12 | _dir.push(obj) 13 | fs.writeFileSync('./database/user/afk.json', JSON.stringify(_dir)) 14 | } 15 | 16 | /** 17 | * Check if user is on AFK state. 18 | * @param {string} userId 19 | * @param {object} _dir 20 | * @returns {boolean} 21 | */ 22 | const checkAfkUser = (userId, _dir) => { 23 | let status = false 24 | Object.keys(_dir).forEach((i) => { 25 | if (_dir[i].id === userId) { 26 | status = true 27 | } 28 | }) 29 | return status 30 | } 31 | 32 | /** 33 | * Get user AFK reason. 34 | * @param {string} userId 35 | * @param {object} _dir 36 | * @returns {string} 37 | */ 38 | const getAfkReason = (userId, _dir) => { 39 | let position = null 40 | Object.keys(_dir).forEach((i) => { 41 | if (_dir[i].id === userId) { 42 | position = i 43 | } 44 | }) 45 | if (position !== null) { 46 | return _dir[position].reason 47 | } 48 | } 49 | 50 | /** 51 | * Get user AFK time. 52 | * @param {string} userId 53 | * @param {object} _dir 54 | * @returns {string} 55 | */ 56 | const getAfkTime = (userId, _dir) => { 57 | let position = null 58 | Object.keys(_dir).forEach((i) => { 59 | if (_dir[i].id === userId) { 60 | position = i 61 | } 62 | }) 63 | if (position !== null) { 64 | return _dir[position].time 65 | } 66 | } 67 | 68 | /** 69 | * Get user AFK ID. 70 | * @param {string} userId 71 | * @param {object} _dir 72 | * @returns {string} 73 | */ 74 | const getAfkId = (userId, _dir) => { 75 | let position = null 76 | Object.keys(_dir).forEach((i) => { 77 | if (_dir[i].id === userId) { 78 | position = i 79 | } 80 | }) 81 | if (position !== null) { 82 | return _dir[position].id 83 | } 84 | } 85 | 86 | /** 87 | * Get user AFK index position. 88 | * @param {string} userId 89 | * @param {object} _dir 90 | * @returns {number} 91 | */ 92 | const getAfkPosition = (userId, _dir) => { 93 | let position = null 94 | Object.keys(_dir).forEach((i) => { 95 | if (_dir[i].id === userId) { 96 | position = i 97 | } 98 | }) 99 | return position 100 | } 101 | 102 | module.exports = { 103 | addAfkUser, 104 | checkAfkUser, 105 | getAfkReason, 106 | getAfkTime, 107 | getAfkId, 108 | getAfkPosition 109 | } -------------------------------------------------------------------------------- /function/daily.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | /** 4 | * Add user daily limit. 5 | * @param {string} userId 6 | * @param {string} dir 7 | * @param {object} _dir 8 | */ 9 | const addLimit = (userId, _dir) => { 10 | const obj = { id: userId, time: Date.now() } 11 | _dir.push(obj) 12 | fs.writeFileSync('./database/user/daily.json', JSON.stringify(_dir)) 13 | } 14 | 15 | /** 16 | * Get user time left. 17 | * @param {string} userId 18 | * @param {object} _dir 19 | * @returns {number} 20 | */ 21 | const getLimit = (userId, _dir) => { 22 | let position = null 23 | Object.keys(_dir).forEach((i) => { 24 | if (_dir[i].id === userId) { 25 | position = i 26 | } 27 | }) 28 | if (position !== null) { 29 | return _dir[position].time 30 | } 31 | } 32 | 33 | module.exports = { 34 | addLimit, 35 | getLimit 36 | } -------------------------------------------------------------------------------- /function/index.js: -------------------------------------------------------------------------------- 1 | exports.level = require('./level') 2 | exports.daily = require('./daily') 3 | exports.limit = require('./limit') 4 | exports.register = require('./register') 5 | exports.afk = require('./afk') 6 | exports.reminder = require('./reminder') 7 | exports.premium = require('./premium') 8 | exports.loader = require('./loader') 9 | exports.quizizz = require('./quizizz') -------------------------------------------------------------------------------- /function/level.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | /** 4 | * Get user ID from db. 5 | * @param {string} userId 6 | * @param {object} _dir 7 | * @returns {string} 8 | */ 9 | const getLevelingId = (userId, _dir) => { 10 | let pos = null 11 | let found = false 12 | Object.keys(_dir).forEach((i) => { 13 | if (_dir[i].id === userId) { 14 | pos = i 15 | found = true 16 | } 17 | }) 18 | if (found === false && pos === null) { 19 | const obj = { id: userId, xp: 0, level: 1 } 20 | _dir.push(obj) 21 | fs.writeFileSync('./database/user/level.json', JSON.stringify(_dir)) 22 | return userId 23 | } else { 24 | return _dir[pos].id 25 | } 26 | } 27 | 28 | /** 29 | * Get user level from db. 30 | * @param {string} userId 31 | * @param {object} _dir 32 | * @returns {number} 33 | */ 34 | const getLevelingLevel = (userId, _dir) => { 35 | let pos = null 36 | let found = false 37 | Object.keys(_dir).forEach((i) => { 38 | if (_dir[i].id === userId) { 39 | pos = i 40 | found = true 41 | } 42 | }) 43 | if (found === false && pos === null) { 44 | const obj = { id: userId, xp: 0, level: 1 } 45 | _dir.push(obj) 46 | fs.writeFileSync('./database/user/level.json', JSON.stringify(_dir)) 47 | return 1 48 | } else { 49 | return _dir[pos].level 50 | } 51 | } 52 | 53 | /** 54 | * Get user XP from db. 55 | * @param {string} userId 56 | * @param {object} _dir 57 | * @returns {number} 58 | */ 59 | const getLevelingXp = (userId, _dir) => { 60 | let pos = null 61 | let found = false 62 | Object.keys(_dir).forEach((i) => { 63 | if (_dir[i].id === userId) { 64 | pos = i 65 | found = true 66 | } 67 | }) 68 | if (found === false && pos === null) { 69 | const obj = { id: userId, xp: 0, level: 1 } 70 | _dir.push(obj) 71 | fs.writeFileSync('./database/user/level.json', JSON.stringify(_dir)) 72 | return 0 73 | } else { 74 | return _dir[pos].xp 75 | } 76 | } 77 | 78 | /** 79 | * Add user level to db. 80 | * @param {string} userId 81 | * @param {number} amount 82 | * @param {object} _dir 83 | */ 84 | const addLevelingLevel = (userId, amount, _dir) => { 85 | let position = null 86 | Object.keys(_dir).forEach((i) => { 87 | if (_dir[i].id === userId) { 88 | position = i 89 | } 90 | }) 91 | if (position !== null) { 92 | _dir[position].level += amount 93 | fs.writeFileSync('./database/user/level.json', JSON.stringify(_dir)) 94 | } 95 | } 96 | 97 | /** 98 | * Add user XP to db. 99 | * @param {string} userId 100 | * @param {number} amount 101 | * @param {object} _dir 102 | */ 103 | const addLevelingXp = (userId, amount, _dir) => { 104 | let position = null 105 | Object.keys(_dir).forEach((i) => { 106 | if (_dir[i].id === userId) { 107 | position = i 108 | } 109 | }) 110 | if (position !== null) { 111 | _dir[position].xp += amount 112 | fs.writeFileSync('./database/user/level.json', JSON.stringify(_dir)) 113 | } 114 | } 115 | 116 | /** 117 | * Get user rank. 118 | * @param {string} userId 119 | * @param {object} _dir 120 | * @returns {number} 121 | */ 122 | const getUserRank = (userId, _dir) => { 123 | let position = null 124 | let found = false 125 | _dir.sort((a, b) => (a.xp < b.xp) ? 1 : -1) 126 | Object.keys(_dir).forEach((i) => { 127 | if (_dir[i].id === userId) { 128 | position = i 129 | found = true 130 | } 131 | }) 132 | if (found === false && position === null) { 133 | const obj = { id: userId, xp: 0, level: 1 } 134 | _dir.push(obj) 135 | fs.writeFileSync('./database/user/level.json', JSON.stringify(_dir)) 136 | return 99 137 | } else { 138 | return position + 1 139 | } 140 | } 141 | 142 | // Cooldown XP gains to prevent spam 143 | const xpGain = new Set() 144 | 145 | /** 146 | * Check is user exist in set. 147 | * @param {string} userId 148 | * @returns {boolean} 149 | */ 150 | const isGained = (userId) => { 151 | return !!xpGain.has(userId) 152 | } 153 | 154 | /** 155 | * Add user in set and delete it when it's 1 minute. 156 | * @param {string} userId 157 | */ 158 | const addCooldown = (userId) => { 159 | xpGain.add(userId) 160 | setTimeout(() => { 161 | return xpGain.delete(userId) 162 | }, 60000) // Each minute 163 | } 164 | 165 | module.exports = { 166 | getLevelingId, 167 | getLevelingLevel, 168 | getLevelingXp, 169 | addLevelingLevel, 170 | addLevelingXp, 171 | getUserRank, 172 | isGained, 173 | addCooldown 174 | } -------------------------------------------------------------------------------- /function/limit.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | /** 4 | * Check limit. 5 | * @param {string} userId 6 | * @param {object} _dir 7 | * @param {number} limitCount 8 | * @param {boolean} isPremium 9 | * @param {boolean} isOwner 10 | * @returns {boolean} 11 | */ 12 | const isLimit = (userId, _dir, limitCount, isPremium, isOwner) => { 13 | if (isPremium || isOwner) return false 14 | let found = false 15 | for (let i of _dir) { 16 | if (i.id === userId) { 17 | if (i.limit <= 0) { 18 | found = true 19 | return true 20 | } else { 21 | found = true 22 | return false 23 | } 24 | } 25 | } 26 | if (found === false) { 27 | const obj = { id: userId, limit: limitCount } 28 | _dir.push(obj) 29 | fs.writeFileSync('./database/user/limit.json', JSON.stringify(_dir)) 30 | return false 31 | } 32 | } 33 | 34 | /** 35 | * Add limit to user. 36 | * @param {string} userId 37 | * @param {object} _dir 38 | * @param {boolean} isPremium 39 | * @param {boolean} isOwner 40 | */ 41 | const addLimit = (userId, _dir, isPremium, isOwner) => { 42 | if (isPremium || isOwner) return false 43 | let pos = null 44 | Object.keys(_dir).forEach((i) => { 45 | if (_dir[i].id === userId) { 46 | pos = i 47 | } 48 | }) 49 | if (pos !== null) { 50 | _dir[pos].limit -= 1 51 | fs.writeFileSync('./database/user/limit.json', JSON.stringify(_dir)) 52 | } 53 | } 54 | 55 | /** 56 | * Get user's limit. 57 | * @param {string} userId 58 | * @param {object} _dir 59 | * @param {number} limitCount 60 | * @returns {number} 61 | */ 62 | const getLimit = (userId, _dir, limitCount) => { 63 | let pos = null 64 | let found = false 65 | Object.keys(_dir).forEach((i) => { 66 | if (_dir[i].id === userId) { 67 | pos = i 68 | found = true 69 | } 70 | }) 71 | if (found === false && pos === null) { 72 | const obj = { id: userId, limit: limitCount } 73 | _dir.push(obj) 74 | fs.writeFileSync('./database/user/limit.json', JSON.stringify(_dir)) 75 | return limitCount 76 | } else { 77 | return _dir[pos].limit 78 | } 79 | } 80 | 81 | module.exports = { 82 | isLimit, 83 | addLimit, 84 | getLimit 85 | } -------------------------------------------------------------------------------- /function/loader.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-function */ 2 | const fs = require('fs-extra') 3 | const { color } = require('../tools') 4 | 5 | /** 6 | * Returns an array of files. 7 | * @param {*} dirPath 8 | * @param {string[]} [arrayOfFiles] 9 | * @returns {string[]} 10 | */ 11 | const getAllDirFiles = (dirPath, arrayOfFiles) => { 12 | const files = fs.readdirSync(dirPath) 13 | arrayOfFiles = arrayOfFiles || [] 14 | files.forEach((f) => { 15 | if (fs.statSync(dirPath + '/' + f).isDirectory()) { 16 | arrayOfFiles = getAllDirFiles(dirPath + '/' + f, arrayOfFiles) 17 | } else { 18 | arrayOfFiles.push(f) 19 | } 20 | }) 21 | return arrayOfFiles 22 | } 23 | 24 | /** 25 | * Uncache a changes. 26 | * @param {*} module 27 | */ 28 | const uncache = (module = '.') => { 29 | return new Promise((resolve, reject) => { 30 | try { 31 | delete require.cache[require.resolve(module)] 32 | resolve() 33 | } catch (err) { 34 | reject(err) 35 | } 36 | }) 37 | } 38 | 39 | /** 40 | * Delete file cache. 41 | * @param {*} module 42 | * @param {*} call 43 | */ 44 | const nocache = (module, call = () => {}) => { 45 | console.log(color('[WATCH]', 'orange'), color(`=> '${module}'`, 'yellow'), 'file is now being watched by me!') 46 | fs.watchFile(require.resolve(module), async () => { 47 | await uncache(require.resolve(module)) 48 | call(module) 49 | }) 50 | } 51 | 52 | module.exports = { 53 | getAllDirFiles, 54 | uncache, 55 | nocache 56 | } -------------------------------------------------------------------------------- /function/premium.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const toMs = require('ms') 3 | 4 | /** 5 | * Add premium user. 6 | * @param {string} userId 7 | * @param {string} expired 8 | * @param {object} _dir 9 | */ 10 | const addPremiumUser = (userId, expired, _dir) => { 11 | const obj = { id: userId, expired: Date.now() + toMs(expired) } 12 | _dir.push(obj) 13 | fs.writeFileSync('./database/bot/premium.json', JSON.stringify(_dir)) 14 | } 15 | 16 | /** 17 | * Get premium user index position. 18 | * @param {string} userId 19 | * @param {object} _dir 20 | * @returns {Number} 21 | */ 22 | const getPremiumPosition = (userId, _dir) => { 23 | let position = null 24 | Object.keys(_dir).forEach((i) => { 25 | if (_dir[i].id === userId) { 26 | position = i 27 | } 28 | }) 29 | if (position !== null) { 30 | return position 31 | } 32 | } 33 | 34 | /** 35 | * Get premium user expired. 36 | * @param {string} userId 37 | * @param {object} _dir 38 | * @returns {Number} 39 | */ 40 | const getPremiumExpired = (userId, _dir) => { 41 | let position = null 42 | Object.keys(_dir).forEach((i) => { 43 | if (_dir[i].id === userId) { 44 | position = i 45 | } 46 | }) 47 | if (position !== null) { 48 | return _dir[position].expired 49 | } 50 | } 51 | 52 | /** 53 | * Check if is user premium. 54 | * @param {string} userId 55 | * @param {object} _dir 56 | * @returns {boolean} 57 | */ 58 | const checkPremiumUser = (userId, _dir) => { 59 | let status = false 60 | Object.keys(_dir).forEach((i) => { 61 | if (_dir[i].id === userId) { 62 | status = true 63 | } 64 | }) 65 | return status 66 | } 67 | 68 | /** 69 | * Constantly checking premium. 70 | * @param {object} _dir 71 | */ 72 | const expiredCheck = (_dir) => { 73 | setInterval(() => { 74 | let position = null 75 | Object.keys(_dir).forEach((i) => { 76 | if (Date.now() >= _dir[i].expired) { 77 | position = i 78 | } 79 | }) 80 | if (position !== null) { 81 | console.log(`Premium user expired: ${_dir[position].id}`) 82 | _dir.splice(position, 1) 83 | fs.writeFileSync('./database/bot/premium.json', JSON.stringify(_dir)) 84 | } 85 | }, 1000) 86 | } 87 | 88 | /** 89 | * Get all premium user ID. 90 | * @param {object} _dir 91 | * @returns {string[]} 92 | */ 93 | const getAllPremiumUser = (_dir) => { 94 | const array = [] 95 | Object.keys(_dir).forEach((i) => { 96 | array.push(_dir[i].id) 97 | }) 98 | return array 99 | } 100 | 101 | module.exports = { 102 | addPremiumUser, 103 | getPremiumExpired, 104 | getPremiumPosition, 105 | expiredCheck, 106 | checkPremiumUser, 107 | getAllPremiumUser 108 | } 109 | -------------------------------------------------------------------------------- /function/quizizz.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-async-promise-executor */ 2 | const fetch = require('node-fetch') 3 | 4 | /** 5 | * @typedef QuizizzHack 6 | * @property {string} answers 7 | */ 8 | 9 | /** 10 | * Quizizz Hack Tools. 11 | * @param {string} pin 12 | * @returns {Promise} answers 13 | */ 14 | const quizizz = (pin) => new Promise(async (resolve, reject) => { 15 | if (!pin) return reject('Require Pin Query.') 16 | const Data = await fetch('https://piyo.my.id/hack', { 17 | method: 'POST', 18 | headers: { 19 | 'Accept': 'application/json', 20 | 'Content-Type': 'application/json' 21 | }, 22 | body: JSON.stringify({ pin: pin }) 23 | }) 24 | const Response = await Data.json() 25 | if (Response.status === 400) return reject(Response.message) 26 | resolve(Response) 27 | }) 28 | 29 | module.exports = { 30 | quizizz 31 | } -------------------------------------------------------------------------------- /function/register.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | /** 4 | * Add user to database. 5 | * @param {string} userId 6 | * @param {string} name 7 | * @param {string} time 8 | * @param {string} serial 9 | * @param {object} _dir 10 | */ 11 | const addRegisteredUser = (userId, name, time, serial, _dir) => { 12 | const obj = { id: userId, name: name, time: time, serial: serial } 13 | _dir.push(obj) 14 | fs.writeFileSync('./database/bot/registered.json', JSON.stringify(_dir)) 15 | } 16 | 17 | /** 18 | * Check is user registered. 19 | * @param {string} userId 20 | * @param {object} _dir 21 | * @returns {boolean} 22 | */ 23 | const checkRegisteredUser = (userId, _dir) => { 24 | let status = false 25 | Object.keys(_dir).forEach((i) => { 26 | if (_dir[i].id === userId) { 27 | status = true 28 | } 29 | }) 30 | return status 31 | } 32 | 33 | /** 34 | * Check is user registered from given serial. 35 | * @param {string} serial 36 | * @param {object} _dir 37 | * @returns {boolean} 38 | */ 39 | const checkRegisteredUserFromSerial = (serial, _dir) => { 40 | let status = false 41 | Object.keys(_dir).forEach((i) => { 42 | if (_dir[i].serial === serial) { 43 | status = true 44 | } 45 | }) 46 | return status 47 | } 48 | 49 | /** 50 | * Get registered user ID. 51 | * @param {string} userId 52 | * @param {object} _dir 53 | * @returns {string} 54 | */ 55 | const getRegisteredUserId = (userId, _dir) => { 56 | let position = null 57 | Object.keys(_dir).forEach((i) => { 58 | if (_dir[i].id === userId) { 59 | position = i 60 | } 61 | }) 62 | if (position !== null) { 63 | return _dir[position].id 64 | } 65 | } 66 | 67 | /** 68 | * Check user name from serial. 69 | * @param {string} serial 70 | * @param {object} _dir 71 | * @returns {string} 72 | */ 73 | const getRegisteredNameFromSerial = (serial, _dir) => { 74 | let position = null 75 | Object.keys(_dir).forEach((i) => { 76 | if (_dir[i].serial === serial) { 77 | position = i 78 | } 79 | }) 80 | if (position !== null) { 81 | return _dir[position].name 82 | } 83 | } 84 | 85 | /** 86 | * Check user time registration from serial. 87 | * @param {string} serial 88 | * @param {object} _dir 89 | * @returns {string} 90 | */ 91 | const getRegisteredTimeFromSerial = (serial, _dir) => { 92 | let position = null 93 | Object.keys(_dir).forEach((i) => { 94 | if (_dir[i].serial === serial) { 95 | position = i 96 | } 97 | }) 98 | if (position !== null) { 99 | return _dir[position].time 100 | } 101 | } 102 | 103 | /** 104 | * Check user ID from serial. 105 | * @param {string} serial 106 | * @param {object} _dir 107 | * @returns {string} 108 | */ 109 | const getRegisteredIdFromSerial = (serial, _dir) => { 110 | let position = null 111 | Object.keys(_dir).forEach((i) => { 112 | if (_dir[i].serial === serial) { 113 | position = i 114 | } 115 | }) 116 | if (position !== null) { 117 | return _dir[position].id 118 | } 119 | } 120 | 121 | /** 122 | * Get random user ID. 123 | * @param {object} _dir 124 | * @returns {string} 125 | */ 126 | const getRegisteredRandomId = (_dir) => { 127 | return _dir[Math.floor(Math.random() * _dir.length)].id 128 | } 129 | 130 | /** 131 | * Get position of registered user. 132 | * @param {string} userId 133 | * @param {object} _dir 134 | * @returns {number} 135 | */ 136 | const getRegisteredPosition = (userId, _dir) => { 137 | let position = null 138 | Object.keys(_dir).forEach((i) => { 139 | if (_dir[i].id === userId) { 140 | position = i 141 | } 142 | }) 143 | return position 144 | } 145 | 146 | module.exports = { 147 | addRegisteredUser, 148 | checkRegisteredUser, 149 | checkRegisteredUserFromSerial, 150 | getRegisteredNameFromSerial, 151 | getRegisteredTimeFromSerial, 152 | getRegisteredIdFromSerial, 153 | getRegisteredRandomId, 154 | getRegisteredUserId, 155 | getRegisteredPosition 156 | } 157 | -------------------------------------------------------------------------------- /function/reminder.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const toMs = require('ms') 3 | 4 | /** 5 | * Add reminder to user. 6 | * @param {string} userId 7 | * @param {string} message 8 | * @param {number} time 9 | * @param {object} _dir 10 | */ 11 | const addReminder = (userId, message, time, _dir) => { 12 | const obj = { id: userId, msg: message, time: Date.now() + toMs(time) } 13 | _dir.push(obj) 14 | fs.writeFileSync('./database/user/reminder.json', JSON.stringify(_dir)) 15 | } 16 | 17 | /** 18 | * Get reminder. 19 | * @param {string} userId 20 | * @param {object} _dir 21 | * @returns {number} 22 | */ 23 | const getReminderTime = (userId, _dir) => { 24 | let position = null 25 | Object.keys(_dir).forEach((i) => { 26 | if(_dir[i].id === userId) { 27 | position = i 28 | } 29 | }) 30 | if (position !== null) { 31 | return _dir[position].time 32 | } 33 | } 34 | 35 | /** 36 | * Get reminder message. 37 | * @param {string} userId 38 | * @param {object} _dir 39 | * @returns {string} 40 | */ 41 | const getReminderMsg = (userId, _dir) => { 42 | let position = null 43 | Object.keys(_dir).forEach((i) => { 44 | if (_dir[i].id === userId) { 45 | position = i 46 | } 47 | }) 48 | if (position !== null) { 49 | return _dir[position].msg 50 | } 51 | } 52 | 53 | /** 54 | * Get position of reminder. 55 | * @param {string} userId 56 | * @param {object} _dir 57 | * @returns {number} 58 | */ 59 | const getReminderPosition = (userId, _dir) => { 60 | let position = null 61 | Object.keys(_dir).forEach((i) => { 62 | if (_dir[i].id === userId) { 63 | position = i 64 | } 65 | }) 66 | return position 67 | } 68 | 69 | module.exports = { 70 | addReminder, 71 | getReminderTime, 72 | getReminderMsg, 73 | getReminderPosition 74 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | const { create, Client } = require('@open-wa/wa-automate') 3 | const { color, options } = require('./tools') 4 | const { eng, ind } = require('./message/text/lang/') 5 | const { loader } = require('./function') 6 | const { version, bugs } = require('./package.json') 7 | const { ownerBot } = require('./config.json') 8 | const { groupLimit, memberLimit } = require('./database/bot/setting.json') 9 | const msgHandler = require('./message/index.js') 10 | const figlet = require('figlet') 11 | const fs = require('fs-extra') 12 | const cron = require('node-cron') 13 | const exec = require('await-exec') 14 | 15 | const start = (bocchi = new Client()) => { 16 | console.log(color(figlet.textSync('BocchiBot', 'Larry 3D'), 'cyan')) 17 | console.log(color('=> Bot successfully loaded! Database:', 'yellow'), color(loader.getAllDirFiles('./database').length), color('Library:', 'yellow'), color(loader.getAllDirFiles('./lib').length), color('Function:', 'yellow'), color(loader.getAllDirFiles('./function').length)) 18 | console.log(color('=> Source code version:', 'yellow'), color(version)) 19 | console.log(color('=> Bug? Error? Suggestion? Visit here:', 'yellow'), color(bugs.url)) 20 | console.log(color('[BOCCHI]'), color('BocchiBot is now online!', 'yellow')) 21 | 22 | if (!fs.existsSync('./temp')) { 23 | console.log(color('=> Temp folder not found! Creating temp folder...', 'yellow')) 24 | fs.mkdirSync('./temp/audio', { recursive: true }) 25 | fs.mkdirSync('./temp/video', { recursive: true }) 26 | console.log(color('=> Temp folder successfully created!', 'yellow')) 27 | } 28 | 29 | // Uncomment code below to activate auto-update file changes. 30 | // loader.nocache('../message/index.js', (m) => console.log(color('[WATCH]', 'orange'), color(`=> '${m}'`, 'yellow'), 'file is updated!')) 31 | 32 | bocchi.onStateChanged(async (state) => { 33 | console.log(color('[BOCCHI]'), color(state, 'yellow')) 34 | if (state === 'OPENING') { 35 | await bocchi.refresh() 36 | .catch((err) => { 37 | console.log(color('[ERROR]', 'red'), color(err, 'yellow')) 38 | console.log(color('[BOCCHI]'), color('Initiating force restart...', 'yellow')) 39 | exec('pm2 restart all') 40 | }) 41 | } 42 | if (state === 'UNPAIRED' || state === 'CONFLICT' || state === 'UNLAUNCHED') await bocchi.forceRefocus() 43 | }) 44 | 45 | bocchi.onAddedToGroup(async (chat) => { 46 | const gc = await bocchi.getAllGroups() 47 | console.log(color('[BOCCHI]'), 'Added to a new group. Name:', color(chat.contact.name, 'yellow'), 'Total members:', color(chat.groupMetadata.participants.length, 'yellow')) 48 | if (chat.groupMetadata.participants.includes(ownerBot)) { 49 | await bocchi.sendText(chat.id, eng.addedGroup(chat)) 50 | } else if (gc.length > groupLimit) { 51 | await bocchi.sendText(chat.id, `Max groups reached!\n\nCurrent status: ${gc.length}/${groupLimit}`) 52 | await bocchi.clearChat(chat.id) 53 | await bocchi.leaveGroup(chat.id) 54 | } else if (chat.groupMetadata.participants.length < memberLimit) { 55 | await bocchi.sendText(chat.id, `Need at least ${memberLimit} members in group!`) 56 | await bocchi.clearChat(chat.id) 57 | await bocchi.leaveGroup(chat.id) 58 | } else { 59 | await bocchi.sendText(chat.id, eng.addedGroup(chat)) 60 | } 61 | }) 62 | 63 | bocchi.onMessage((message) => { 64 | // Comment code below to activate auto-update. Then, uncomment require code below msgHandler. 65 | msgHandler(bocchi, message) 66 | // require('./message/index.js')(bocchi, message) 67 | }) 68 | 69 | bocchi.onIncomingCall(async (callData) => { 70 | await bocchi.sendText(callData.peerJid, eng.blocked(ownerBot)) 71 | await bocchi.contactBlock(callData.peerJid) 72 | console.log(color('[BLOCK]', 'red'), color(`${callData.peerJid} has been blocked.`, 'yellow')) 73 | }) 74 | 75 | // Clear chats every 12 hour 76 | cron.schedule('0 */12 * * *', async () => { 77 | const allChats = await bocchi.getAllChats() 78 | for (let chats of allChats) { 79 | if (chats.isGroup === true) { 80 | console.log(color('[BOCCHI]'), color('Clearing chats...', 'yellow')) 81 | await bocchi.clearChat(chats.id) 82 | } else { 83 | await bocchi.deleteChat(chats.id) 84 | } 85 | } 86 | console.log(color('[BOCCHI]'), color('Success cleared all chats!', 'yellow')) 87 | }) 88 | 89 | bocchi.onGlobalParticipantsChanged(async (event) => { 90 | const _welcome = JSON.parse(fs.readFileSync('./database/group/welcome.json')) 91 | const isWelcome = _welcome.includes(event.chat) 92 | const gcChat = await bocchi.getChatById(event.chat) 93 | const pcChat = await bocchi.getContact(event.who) 94 | let { pushname, verifiedName, formattedName } = pcChat 95 | pushname = pushname || verifiedName || formattedName 96 | const { groupMetadata } = gcChat 97 | const botNumbers = await bocchi.getHostNumber() + '@c.us' 98 | try { 99 | if (event.action === 'add' && event.who !== botNumbers && isWelcome) { 100 | await bocchi.sendText(event.chat, `Welcome, ${pushname}! You are the *${groupMetadata.participants.length}* member.`) 101 | } else if (event.action === 'remove' && event.who !== botNumbers && isWelcome) { 102 | await bocchi.sendText(event.chat, `Bye, ${pushname}. We will miss you. :(`) 103 | } 104 | } catch (err) { 105 | console.error(err) 106 | } 107 | }) 108 | } 109 | 110 | create(options(start)) 111 | .then((bocchi) => start(bocchi)) 112 | .catch((err) => console.error(err)) -------------------------------------------------------------------------------- /lib/downloader.js: -------------------------------------------------------------------------------- 1 | const { twitter } = require('video-url-link') 2 | const ytdl = require('ytdl-core') 3 | const fs = require('fs-extra') 4 | const { createSerial } = require('../tools/index.js') 5 | 6 | /** 7 | * @typedef TwitterData 8 | * @property {string} full_text 9 | * @property {object[]} variants 10 | */ 11 | 12 | /** 13 | * Twitter video downloader. 14 | * @param {string} url 15 | * @returns {Promise} 16 | */ 17 | const tweet = (url) => new Promise((resolve, reject) => { 18 | twitter.getInfo(url, {}, (error, info) => { 19 | if (error) { 20 | reject(error) 21 | } else { 22 | resolve(info) 23 | } 24 | }) 25 | }) 26 | 27 | /** 28 | * @typedef YoutubeData 29 | * @property {string} title 30 | * @property {string} path 31 | */ 32 | 33 | /** 34 | * YouTube video downloader. 35 | * @param {string} url 36 | * @param {number} sender 37 | * @returns {Promise} video path 38 | */ 39 | const yt = (url, sender) => new Promise((resolve, reject) => { 40 | if (ytdl.validateURL(url)) { 41 | ytdl.getBasicInfo(url) 42 | .then((metadata) => { 43 | const output = `temp/${sender}_${createSerial(5)}.mp4` 44 | ytdl(url) 45 | .pipe(fs.createWriteStream(output)) 46 | .on('finish', () => { 47 | const obj = { 48 | title: metadata.videoDetails.title, 49 | path: output 50 | } 51 | resolve(obj) 52 | }) 53 | .on('error', (err) => { 54 | reject(err) 55 | }) 56 | }) 57 | } else { 58 | reject('Not a valid URL.') 59 | } 60 | }) 61 | 62 | module.exports = { 63 | tweet, 64 | yt 65 | } 66 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | exports.weeaboo = require('./weeaboo') 2 | exports.downloader = require('./downloader') 3 | -------------------------------------------------------------------------------- /lib/weeaboo.js: -------------------------------------------------------------------------------- 1 | const { fetchJson } = require('../tools/fetcher') 2 | 3 | /** 4 | * Get random waifu image. 5 | * @param {boolean} [nsfw=false] 6 | * @returns {Promise} 7 | */ 8 | const waifu = (nsfw) => new Promise((resolve, reject) => { 9 | if (nsfw === true) { 10 | console.log('Get NSFW waifu image...') 11 | fetchJson('https://waifu.pics/api/nsfw/waifu') 12 | .then((result) => resolve(result)) 13 | .catch((err) => reject(err)) 14 | } else { 15 | console.log('Get SFW waifu image...') 16 | fetchJson('https://waifu.pics/api/sfw/waifu') 17 | .then((result) => resolve(result)) 18 | .catch((err) => reject(err)) 19 | } 20 | }) 21 | 22 | /** 23 | * Get anime source from image. 24 | * @param {string} url 25 | * @returns {Promise} 26 | */ 27 | const wait = (url) => new Promise((resolve, reject) => { 28 | console.log('Searching for source...') 29 | fetchJson(`https://api.trace.moe/search?anilistInfo&url=${encodeURIComponent(url)}`) 30 | .then((result) => resolve(result)) 31 | .catch((err) => reject(err)) 32 | }) 33 | 34 | module.exports = { 35 | waifu, 36 | wait 37 | } 38 | -------------------------------------------------------------------------------- /message/text/lang/eng.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable quotes */ 2 | const { prefix } = require('../../../config.json') 3 | 4 | exports.unreg = () => { 5 | return `Successfully unregistered!` 6 | } 7 | 8 | exports.wait = () => { 9 | return `Please wait a moment...` 10 | } 11 | 12 | exports.ok = () => { 13 | return `Done!` 14 | } 15 | 16 | exports.videoLimit = () => { 17 | return `Video/GIF size is too large!` 18 | } 19 | 20 | exports.wrongFormat = () => { 21 | return `Incorrect format! Please check usage at *${prefix}menu*` 22 | } 23 | 24 | exports.emptyMess = () => { 25 | return `Please enter the message!` 26 | } 27 | 28 | exports.cmdNotFound = (cmd) => { 29 | return `Command *${prefix}${cmd}* not found!` 30 | } 31 | 32 | exports.blocked = (ownerNumber) => { 33 | return `The bot cannot receive calls. You have been blocked because breaking the rules!\n\nContact the owner: wa.me/${ownerNumber.replace('@c.us', '')}` 34 | } 35 | 36 | exports.ownerOnly = () => { 37 | return `This command can only be used by owner!` 38 | } 39 | 40 | exports.groupOnly = () => { 41 | return `This command can only be used in group!` 42 | } 43 | 44 | exports.adminOnly = () => { 45 | return `This command can only be used by group admins!` 46 | } 47 | 48 | exports.addedGroup = (chat) => { 49 | return `Thanks for inviting me, members of *${chat.contact.name}*!\n\nPlease register in *private chat* by typing:\n*${prefix}register* name` 50 | } 51 | 52 | exports.listBlock = (blockNumber) => { 53 | return ` 54 | *── 「 HALL OF SHAME 」 ──* 55 | 56 | Total blocked: *${blockNumber.length}* user(s)\n 57 | ` 58 | } 59 | 60 | exports.notPremium = () => { 61 | return `Sorry! This command can only be used by premium users.` 62 | } 63 | 64 | exports.notAdmin = () => { 65 | return `The user is not an admin!` 66 | } 67 | 68 | exports.adminAlready = () => { 69 | return `Cannot promote user who is an admin already!` 70 | } 71 | 72 | exports.botNotPremium = () => { 73 | return `This bot doesn't support premium commands. Please contact the owner of this bot.` 74 | } 75 | 76 | exports.botNotAdmin = () => { 77 | return `Make the bot as admin first!` 78 | } 79 | 80 | exports.notRegistered = () => { 81 | return `You haven't registered in our database!\n\nPlease register in *private chat* by typing:\n*${prefix}register* name` 82 | } 83 | 84 | exports.registered = (name, userId, time, serial) => { 85 | return ` 86 | *── 「 REGISTRATION 」 ──* 87 | 88 | Your account has been created with data below: 89 | ➸ *Name*: ${name} 90 | ➸ *ID*: ${userId} 91 | ➸ *Registered on*: ${time} 92 | ➸ *Serial*: ${serial} 93 | 94 | Note: 95 | Don't share your *serial* to anyone! 96 | 97 | Type *${prefix}rules* to see the rules. 98 | ` 99 | } 100 | 101 | exports.registeredAlready = () => { 102 | return `You've registered before.` 103 | } 104 | 105 | exports.received = (pushname) => { 106 | return `Hello ${pushname}!\nThanks for the report, we will work on it ASAP.` 107 | } 108 | 109 | exports.daily = (time) => { 110 | return `Sorry, but you've reached your limit using this command.\nPlease wait for *${time.hours}* hour(s) *${time.minutes}* minute(s) *${time.seconds}* second(s) more.` 111 | } 112 | 113 | exports.profile = (username, status, premi, benet, adm, level, requiredXp, xp) => { 114 | return ` 115 | *── 「 USER INFO」 ──* 116 | 117 | ➸ *Username*: ${username} 118 | ➸ *Status*: ${status} 119 | ➸ *Premium*: ${premi} 120 | ➸ *Banned*: ${benet} 121 | ➸ *Admin*: ${adm} 122 | 123 | =_=_=_=_=_=_=_=_=_=_=_=_= 124 | 125 | *── 「 PROGRESS 」 ──* 126 | 127 | ➸ *Level*: ${level} 128 | ➸ *XP*: ${xp} / ${requiredXp} 129 | ` 130 | } 131 | 132 | exports.detectorOn = (name, formattedTitle) => { 133 | return ` 134 | *── 「 ANTI GROUP LINK 」 ──* 135 | 136 | Announcement for all *${(name || formattedTitle)}* members. 137 | This group has a group link detector, if someone sends a group link then he'll be kicked out immediately. 138 | 139 | Thanks for your attention. 140 | - Admin *${(name || formattedTitle)}* 141 | ` 142 | } 143 | 144 | exports.linkDetected = () => { 145 | return ` 146 | *── 「 ANTI GROUP LINK 」 ──* 147 | 148 | You sent a group chat link! 149 | Sorry, but you have to leave... 150 | ` 151 | } 152 | 153 | exports.detectorOff = () => { 154 | return `Anti-group link feature was successfully *disabled*!` 155 | } 156 | 157 | exports.detectorOnAlready = () => { 158 | return `Anti-group link feature has been enabled before.` 159 | } 160 | 161 | exports.antiNsfwOn = (name, formattedTitle) => { 162 | return ` 163 | *── 「 ANTI NSFW LINK 」 ──* 164 | 165 | Announcement for all *${(name || formattedTitle)}* members. 166 | This group has a NSFW link detector, if someone sends a NSFW link then he'll be kicked out immediately. 167 | 168 | Thanks for your attention. 169 | - Admin *${(name || formattedTitle)}* 170 | ` 171 | } 172 | 173 | exports.antiNsfwOff = () => { 174 | return `Anti-NSFW link feature was successfully *disabled*!` 175 | } 176 | 177 | exports.antiNsfwOnAlready = () => { 178 | return `Anti-NSFW link feature has been enabled before.` 179 | } 180 | 181 | exports.antiBadWordsOn = (name, formattedTitle) => { 182 | return ` 183 | *── 「 ANTI BAD WORDS 」 ──* 184 | 185 | Announcement for all *${(name || formattedTitle)}* members. 186 | This group has a bad words detector, if someone sends a bad words/profane words then the related message will be deleted. 187 | 188 | Thanks for your attention. 189 | - Admin *${(name || formattedTitle)}* 190 | ` 191 | } 192 | 193 | exports.antiBadWordsOff = () => { 194 | return `Anti-bad words feature was successfully *disabled*!` 195 | } 196 | 197 | exports.antiBadWordsOnAlready = () => { 198 | return `Anti-bad words feature has been enabled before.` 199 | } 200 | 201 | exports.antiBadWordsError = () => { 202 | return `Anti-bad words feature is currently *off*, please enable it first.` 203 | } 204 | 205 | exports.levelingOn = () => { 206 | return `Leveling feature was successfully *enabled*!` 207 | } 208 | 209 | exports.levelingOff = () => { 210 | return `Leveling feature was successfully *disabled*!` 211 | } 212 | 213 | exports.levelingOnAlready = () => { 214 | return `Leveling feature has been enabled before.` 215 | } 216 | 217 | exports.levelingNotOn = () => { 218 | return `Leveling feature hasn't been enabled!` 219 | } 220 | 221 | exports.levelNull = () => { 222 | return `You don't have any level yet!` 223 | } 224 | 225 | exports.welcome = (event) => { 226 | return `Welcome @${event.who.replace('@c.us', '')}!` 227 | } 228 | 229 | exports.welcomeOn = () => { 230 | return `Welcome feature was successfully *enabled*!` 231 | } 232 | 233 | exports.welcomeOff = () => { 234 | return `Welcome feature was successfully *disabled*!` 235 | } 236 | 237 | exports.welcomeOnAlready = () => { 238 | return `Welcome feature has been enabled before.` 239 | } 240 | 241 | exports.minimalDb = () => { 242 | return `Need at least *10* users that have a level in database!` 243 | } 244 | 245 | exports.autoStikOn = () => { 246 | return `Auto-sticker feature was successfully *enabled*!` 247 | } 248 | 249 | exports.autoStikOff = () => { 250 | return `Auto-sticker feature was successfully *disabled*!` 251 | } 252 | 253 | exports.autoStikOnAlready = () => { 254 | return `Auto-sticker feature has been enabled before.` 255 | } 256 | 257 | exports.afkOn = (pushname, reason) => { 258 | return ` 259 | *── 「 AFK MODE 」 ──* 260 | 261 | AFK feature has been successfully *enabled*! 262 | ➸ *Username*: ${pushname} 263 | ➸ *Reason*: ${reason} 264 | ` 265 | } 266 | 267 | exports.afkOnAlready = () => { 268 | return `AFK feature has been enabled before.` 269 | } 270 | 271 | exports.afkMentioned = (getReason, getTime) => { 272 | return ` 273 | *── 「 AFK MODE 」 ──* 274 | 275 | Ssshhh! This person is currently AFK! 276 | ➸ *Reason*: ${getReason} 277 | ➸ *Since*: ${getTime} 278 | ` 279 | } 280 | 281 | exports.afkDone = (pushname) => { 282 | return `*${pushname}* is back from AFK!` 283 | } 284 | 285 | exports.gcMute = () => { 286 | return ` 287 | *── 「 MUTED 」 ──* 288 | 289 | Only admins who can send message in this group. 290 | ` 291 | } 292 | 293 | exports.gcUnmute = () => { 294 | return ` 295 | *── 「 UNMUTED 」 ──* 296 | 297 | All members can send message in this group now. 298 | ` 299 | } 300 | 301 | exports.notNum = (q) => { 302 | return `"${q}", are not a numbers!` 303 | } 304 | 305 | exports.registeredFound = (name, time, serial, userId) => { 306 | return ` 307 | *── 「 REGISTERED 」 ──* 308 | 309 | Account has been found! 310 | ➸ *Name*: ${name} 311 | ➸ *ID*: ${userId} 312 | ➸ *Registered time*: ${time} 313 | ➸ *Serial*: ${serial} 314 | ` 315 | } 316 | 317 | exports.registeredNotFound = (serial) => { 318 | return `Account with serial: *${serial}* not found!` 319 | } 320 | 321 | exports.pcOnly = () => { 322 | return `This command can only be used in private chat!` 323 | } 324 | 325 | exports.linkNsfw = () => { 326 | return ` 327 | *── 「 ANTI NSFW LINK 」 ──* 328 | 329 | You've sent a group link! 330 | Sorry, but you have to leave... 331 | ` 332 | } 333 | 334 | exports.fakeLink = () => { 335 | return `The link you sent is suspicious, for the safety of the group I will kick you out.\nBye~.` 336 | } 337 | 338 | exports.muteChatOn = () => { 339 | return `Successfully *mute* bot for this group!` 340 | } 341 | 342 | exports.muteChatOff = () => { 343 | return `Successfully *unmute* bot for this group!` 344 | } 345 | 346 | exports.muteChatOnAlready = () => { 347 | return `Bot is already muted in this group!` 348 | } 349 | 350 | exports.limit = () => { 351 | return ` 352 | *── 「 LIMIT 」 ──* 353 | 354 | You ran out of usage limit! Please do the following: 355 | ❏ *_Wait until 12:00 AM (UTC+7)_* 356 | ` 357 | } 358 | 359 | exports.reminderOn = (messRemind, parsedTime, sender) => { 360 | return ` 361 | *── 「 REMINDER 」 ──* 362 | 363 | Reminder has been set! 364 | ➸ *Message*: ${messRemind} 365 | ➸ *Duration*: ${parsedTime.hours} hour(s) ${parsedTime.minutes} minute(s) ${parsedTime.seconds} second(s) 366 | ➸ *For*: @${sender.id.replace('@c.us', '')} 367 | ` 368 | } 369 | 370 | exports.reminderAlert = (messRemind, sender) => { 371 | return ` 372 | *── 「 REMINDER 」 ──* 373 | 374 | ⏰ @${sender.id.replace('@c.us', '')} ⏰ 375 | ➸ *Message*: ${messRemind}` 376 | } 377 | 378 | exports.nameChanged = (q) => { 379 | return `Username has been changed to *${q}*` 380 | } 381 | 382 | exports.menu = (jumlahUser, level, xp, role, pushname, requiredXp, premium) => { 383 | return ` 384 | *── 「 WELCOME 」 ──* 385 | 386 | ====================== 387 | ➸ *Name*: ${pushname} 388 | ➸ *Level*: ${level} 389 | ➸ *XP*: ${xp} / ${requiredXp} 390 | ➸ *Role*: ${role} 391 | ➸ *Premium*: ${premium} 392 | ====================== 393 | 394 | Total registered: *${jumlahUser}* 395 | 396 | *[1]* Downloader 397 | *[2]* Bot 398 | *[3]* Misc 399 | *[4]* Sticker 400 | *[5]* Weeaboo 401 | *[6]* Fun 402 | *[7]* Moderation 403 | *[8]* Owner 404 | *[9]* Leveling 405 | *[10]* AI 406 | 407 | Type *${prefix}menu* index_number to open the selected page menu. 408 | 409 | Note: 410 | The bot has a cooldown for *5 seconds* every time you use it. 411 | ` 412 | } 413 | 414 | exports.menuDownloader = () => { 415 | return ` 416 | *── 「 DOWNLOADER 」 ──* 417 | 418 | 1. *${prefix}twitter* 419 | Download Twitter media. 420 | Aliases: *twt* 421 | Usage: *${prefix}twitter* link 422 | 423 | 2. *${prefix}youtube* 424 | Download YouTube video. 425 | Aliases: *yt* 426 | Usage: *${prefix}youtube* link 427 | 428 | _Index of [1]_ 429 | ` 430 | } 431 | 432 | exports.menuBot = () => { 433 | return ` 434 | *── 「 BOT 」 ──* 435 | 436 | 1. *${prefix}rules* 437 | Must read. 438 | Aliases: *rule* 439 | Usage: *${prefix}rules* 440 | 441 | 2. *${prefix}menu* 442 | Display available commands. 443 | Aliases: - 444 | Usage: *${prefix}menu* index_number 445 | 446 | 3. *${prefix}status* 447 | Display bot status. 448 | Aliases: *stats* 449 | Usage: *${prefix}status* 450 | 451 | 4. *${prefix}listblock* 452 | Check blocked numbers. 453 | Aliases: - 454 | Usage: *${prefix}listblock* 455 | 456 | 5. *${prefix}ping* 457 | Check bot speed. 458 | Aliases: *p* 459 | Usage: *${prefix}ping* 460 | 461 | 6. *${prefix}delete* 462 | Delete messages from bot. 463 | Aliases: *del* 464 | Usage: Reply to deleted messages with a caption *${prefix}delete* 465 | 466 | 7. *${prefix}report* 467 | Report bugs to owner. 468 | Aliases: - 469 | Usage: *${prefix}report* text 470 | 471 | 8. *${prefix}tos* 472 | Terms of service. 473 | Aliases: - 474 | Usage: *${prefix}tos* 475 | 476 | 9. *${prefix}join* 477 | Join a group via link. 478 | Aliases: - 479 | Usage: *${prefix}join* group_link 480 | 481 | 10. *${prefix}ownerbot* 482 | Send owner contact. 483 | Aliases: - 484 | Usage: *${prefix}ownerbot* 485 | 486 | 11. *${prefix}getpic* 487 | Send user's profile pic. 488 | Aliases: - 489 | Usage: *${prefix}getpic* @user/62812xxxxxxxx 490 | 491 | 12. *${prefix}premiumcheck* 492 | Check your remaining premium time limit. 493 | Aliases: *cekpremium* 494 | Usage: *${prefix}premiumcheck* 495 | 496 | 13. *${prefix}premiumlist* 497 | Premium user list. 498 | Aliases: *listpremium* 499 | Usage: *${prefix}premiumlist* 500 | 501 | 14. *${prefix}limit* 502 | Check your remaining limit. 503 | Aliases: - 504 | Usage: *${prefix}limit* 505 | 506 | 15. *${prefix}serial* 507 | Check your bio using serial. 508 | Aliases: - 509 | Usage: *${prefix}serial* serial 510 | 511 | 16. *${prefix}runtime* 512 | Check your host runtime. 513 | Aliases: - 514 | Usage: *${prefix}runtime* 515 | 516 | 17. *${prefix}unregister* 517 | Unregister your account. 518 | Aliases: *unreg* 519 | Usage: *${prefix}unregister* 520 | 521 | _Index of [2]_ 522 | ` 523 | } 524 | 525 | exports.menuMisc = () => { 526 | return ` 527 | *── 「 MISC 」 ──* 528 | 529 | 1. *${prefix}say* 530 | The bot will repeat your message. 531 | Aliases: - 532 | Usage: *${prefix}say* text 533 | 534 | 2. *${prefix}tts* 535 | Create a text to speech audio. You can find language code here https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 536 | Aliases: - 537 | Usage: *${prefix}tts* language_code | text 538 | 539 | 3. *${prefix}afk* 540 | Set your account to AFK mode. 541 | Aliases: - 542 | Usage: *${prefix}afk* reason. Send any message to group to disable. 543 | 544 | 4. *${prefix}math* 545 | A calculator. 546 | * = multiplication 547 | + = addition 548 | - = subtraction 549 | / = division 550 | Aliases: - 551 | Usage: *${prefix}math* 12*12 552 | 553 | 5. *${prefix}reminder* 554 | Reminder. 555 | *s* - seconds 556 | *m* - minutes 557 | *h* - hours 558 | *d* - days 559 | Aliases: - 560 | Usage: *${prefix}reminder* 10s | reminder_message 561 | 562 | 6. *${prefix}imagetourl* 563 | Image uploader. 564 | Aliases: *imgtourl* 565 | Usage: Send images with caption *${prefix}imagetourl* or reply to the image with a caption *${prefix}imagetourl* 566 | 567 | 7. *${prefix}genshininfo* 568 | Genshin Impact characters info. 569 | Aliases: *genshin* 570 | Usage: *${prefix}genshininfo* chara_name 571 | 572 | 8. *${prefix}translate* 573 | Translate a text. 574 | Aliases: *tl* 575 | Usage: *${prefix}translate* text | code_lang 576 | 577 | 9. *${prefix}tomp3* 578 | Convert a video to audio only (MP3). 579 | Aliases: - 580 | Usage: Send a video with caption *${prefix}tomp3* or reply video with a caption *${prefix}tomp3* 581 | 582 | 10. *${prefix}bass* 583 | Bass boost. 584 | Aliases: - 585 | Usage: Reply audio/voice with caption *${prefix}bass* dB_level. 586 | 587 | 11. *${prefix}nightcore* 588 | Create a nightcore effect. 589 | Aliases: - 590 | Usage: Reply audio/voice with caption *${prefix}nightcore* 591 | 592 | 12. *${prefix}google* 593 | Search through Google. 594 | Aliases: *googlesearch* 595 | Usage: *${prefix}google* query 596 | 597 | 13. *${prefix}toptt* 598 | Create PTT audio. 599 | Aliases: *ptt* 600 | Usage: Reply audio/voice with caption *${prefix}toptt* 601 | 602 | _Index of [3]_ 603 | ` 604 | } 605 | 606 | exports.menuSticker = () => { 607 | return ` 608 | *── 「 STICKER 」 ──* 609 | 610 | 1. *${prefix}sticker* 611 | Create stickers from images sent or replied. 612 | Aliases: *stiker* 613 | Usage: Send images with caption *${prefix}sticker* or reply to the images with a caption *${prefix}sticker* 614 | 615 | 2. *${prefix}stickergif* 616 | Create stickers from videos/GIFs. 617 | Aliases: *stikergif* *sgif* 618 | Usage: Send videos/GIFs with caption *${prefix}stickergif* or reply to the videos/GIFs with a caption *${prefix}stickergif* 619 | 620 | 3. *${prefix}stickertoimg* 621 | Convert sticker to image. 622 | Aliases: *stikertoimg* *toimg* 623 | Usage: Reply to the stickers with a caption *${prefix}stickertoimg* 624 | 625 | 4. *${prefix}stickerwm* 626 | Create a sticker with metadata/WM. 627 | Aliases: *stcwm* 628 | Usage: Send images with caption *${prefix}stickerwm* pack_name | author_name or reply to the image with a caption *${prefix}stickerwm* pack_name | author_name 629 | 630 | 5. *${prefix}stickermeme* 631 | Create a sticker meme. 632 | Aliases: *stcmeme* 633 | Usage: Send images with caption *${prefix}sticker* upper_text | bottom_text or reply to the images with a caption *${prefix}sticker* upper_text | bottom_text 634 | 635 | 6. *${prefix}takestick* 636 | Edit sticker metadata. 637 | Aliases: *take* 638 | Usage: Reply to the stickers with a caption *${prefix}takestick* pack_name | author_name 639 | 640 | 7. *${prefix}stickernobg* 641 | Create stickers from images sent or replied with blank background. 642 | Aliases: *take* 643 | Usage: Send images with caption *${prefix}stickernobg* or reply to the images with a caption *${prefix}stickernobg* 644 | 645 | _Index of [4]_ 646 | ` 647 | } 648 | 649 | exports.menuWeeaboo = () => { 650 | return ` 651 | *── 「 WEEABOO 」 ──* 652 | 653 | 1. *${prefix}neko* 654 | Send a neko girl photo. 655 | Aliases: - 656 | Usage: *${prefix}neko* 657 | 658 | 2. *${prefix}wallpaper* 659 | Send anime wallpapers. 660 | Aliases: *wp* 661 | Usage: *${prefix}wallpaper* 662 | 663 | 3. *${prefix}kemono* 664 | Send kemonomimi girl photos. 665 | Aliases: - 666 | Usage: *${prefix}kemono* 667 | 668 | 4. *${prefix}wait* 669 | Search anime source from the screenshots scene. 670 | Aliases: - 671 | Usage: Send screenshots with caption *${prefix}wait* or reply to the screenshots with a caption *${prefix}wait* 672 | 673 | 5. *${prefix}source* 674 | Look for sources from the doujin panel, illustrations, and images related to anime. 675 | Aliases: *sauce* 676 | Usage: Send images with caption *${prefix}source* or reply to the images with a caption *${prefix}source* 677 | 678 | 6. *${prefix}waifu* 679 | Send random waifu photos. 680 | Aliases: - 681 | Usage: *${prefix}waifu* 682 | 683 | _Index of [5]_ 684 | ` 685 | } 686 | 687 | exports.menuFun = () => { 688 | return ` 689 | *── 「 FUN 」 ──* 690 | 691 | 1. *${prefix}triggered* 692 | Apply a triggered effect to image. 693 | Aliases: - 694 | Usage: Send image with caption *${prefix}triggered* or reply to someone message with caption *${prefix}triggered* or you can directly use *${prefix}triggered* 695 | 696 | 2. *${prefix}kiss* 697 | Kiss someone ( ͡° ͜ʖ ͡°). 698 | Aliases: - 699 | Usage: Send image with caption *${prefix}kiss* or reply image with caption *${prefix}kiss* 700 | 701 | 3. *${prefix}profile* 702 | Check my profile. 703 | Aliases: *me* 704 | Usage: *${prefix}profile* 705 | 706 | 4. *${prefix}trash* 707 | Trash? 708 | Aliases: - 709 | Usage: *${prefix}trash* 710 | 711 | 5. *${prefix}hitler* 712 | Worse than hitler. 713 | Aliases: - 714 | Usage: *${prefix}hitler* 715 | 716 | _Index of [6]_ 717 | ` 718 | } 719 | 720 | exports.menuModeration = () => { 721 | return ` 722 | *── 「 MODERATION 」 ──* 723 | 724 | 1. *${prefix}add* 725 | Add users to group. 726 | Aliases: - 727 | Usage: *${prefix}add* 628xxxxxxxxxx 728 | 729 | 2. *${prefix}kick* 730 | Remove members from the group. 731 | Aliases: - 732 | Usage: *${prefix}kick* @member1 733 | 734 | 3. *${prefix}promote* 735 | Promote member to become admin. 736 | Aliases: - 737 | Usage: *${prefix}promote* @member1 738 | 739 | 4. *${prefix}demote* 740 | Demote member from admin. 741 | Aliases: - 742 | Usage: *${prefix}demote* @member1 743 | 744 | 5. *${prefix}leave* 745 | Leave bot from group. 746 | Aliases: - 747 | Usage: *${prefix}leave* 748 | 749 | 6. *${prefix}everyone* 750 | Mention all group members. 751 | Aliases: - 752 | Usage: *${prefix}everyone* 753 | 754 | 7. *${prefix}groupicon* 755 | Change group icon. 756 | Aliases: - 757 | Usage: Send images with caption *${prefix}groupicon* or reply to the images with a caption *${prefix}groupicon* 758 | 759 | 8. *${prefix}antilink* 760 | Toogle anti-group link feature. 761 | Aliases: - 762 | Usage: *${prefix}antilink* enable/disable 763 | 764 | 9. *${prefix}welcome* 765 | Toogle welcome feature. 766 | Aliases: - 767 | Usage: *${prefix}welcome* enable/disable 768 | 769 | 10. *${prefix}autosticker* 770 | Toogle auto-sticker feature. Every sended image will made into a sticker. 771 | Aliases: *autostiker autostik* 772 | Usage: *${prefix}autostiker* enable/disable 773 | 774 | 11. *${prefix}antinsfw* 775 | Toogle anti-NSFW link. 776 | Aliases: - 777 | Usage: *${prefix}antinsfw* enable/disable 778 | 779 | 12. *${prefix}mutegc* 780 | Set group to admin only who can send a message. 781 | Aliases: - 782 | Usage: *${prefix}mutegc* enable/disable 783 | 784 | 13. *${prefix}grouplink* 785 | Send a invite link of current group. 786 | Aliases: - 787 | Usage: *${prefix}grouplink* 788 | 789 | 14. *${prefix}revoke* 790 | Revoke invite link of current group. 791 | Aliases: - 792 | Usage: *${prefix}revoke* 793 | 794 | 15. *${prefix}leveling* 795 | Toogle leveling feature. 796 | Aliases: - 797 | Usage: *${prefix}leveling* enable/disable 798 | 799 | 16. *${prefix}badwords* 800 | Setting up anti-bad words feature. 801 | Aliases: *badword* 802 | Usage: *${prefix}badwords* enable/disable or add/remove to add/remove a blacklist words. 803 | 804 | _Index of [7]_ 805 | ` 806 | } 807 | 808 | exports.menuOwner = () => { 809 | return ` 810 | *── 「 OWNER 」 ──* 811 | 812 | 1. *${prefix}bc* 813 | Create a broadcast. 814 | Aliases: - 815 | Usage: *${prefix}bc* text 816 | 817 | 2. *${prefix}clearall* 818 | Deletes all chats on the bot account. 819 | Aliases: - 820 | Usage: *${prefix}clearall* 821 | 822 | 3. *${prefix}getses* 823 | Take a screenshot of the session from the bot account. 824 | Aliases: - 825 | Usage: *${prefix}getses* 826 | 827 | 4. *${prefix}ban* 828 | Add/remove banned users. 829 | Aliases: - 830 | Usage: *${prefix}ban* add/del @user/62812xxxxxxxx 831 | 832 | 5. *${prefix}leaveall* 833 | Leave from all groups. 834 | Aliases: - 835 | Usage: *${prefix}leaveall* 836 | 837 | 6. *${prefix}eval* 838 | Evaluate the JavaScript code. 839 | Aliases: *ev* 840 | Usage: *${prefix}eval* 841 | 842 | 7. *${prefix}shutdown* 843 | Shutdown bot. 844 | Aliases: - 845 | Usage: *${prefix}shutdown* 846 | 847 | 8. *${prefix}premium* 848 | Add/remove premium user. 849 | *s* - seconds 850 | *m* - minutes 851 | *h* - hours 852 | *d* - days 853 | Aliases: - 854 | Usage: *${prefix}premium* add/del @user/62812xxxxxxxx 30d 855 | 856 | 9. *${prefix}setstatus* 857 | Set about me. 858 | Aliases: *setstatus setstat* 859 | Usage: *${prefix}status* text 860 | 861 | 10. *${prefix}serial* 862 | Check user's serial. 863 | Aliases: - 864 | Usage: *${prefix}serial* user_serial 865 | 866 | 11. *${prefix}exif* 867 | Adjust your sticker WM. 868 | Aliases: - 869 | Usage: *${prefix}exif* pack_name | author_name 870 | 871 | 12. *${prefix}mute* 872 | Mute all users. 873 | Aliases: - 874 | Usage: Use *${prefix}mute* to mute and use *${prefix}mute* once again to unmute. 875 | 876 | 13. *${prefix}setname* 877 | Change bot's name. Maximum 25 characters. 878 | Aliases: - 879 | Usage: *${prefix}name* new_username 880 | 881 | 14. *${prefix}block* 882 | Block user. 883 | Aliases: *blok* 884 | Usage: *${prefix}block* @user/62812xxxxxxxx 885 | 886 | 15. *${prefix}unblock* 887 | Unblock user. 888 | Aliases: *unblok* 889 | Usage: *${prefix}unblock* @user/62812xxxxxxxx 890 | 891 | 16. *${prefix}xp* 892 | Add XP to someone. 893 | Aliases: - 894 | Usage: *${prefix}xp* @user amount_xp 895 | 896 | _Index of [8]_ 897 | ` 898 | } 899 | 900 | exports.menuLeveling = () => { 901 | return ` 902 | *── 「 LEVELING 」 ──* 903 | 904 | 1. *${prefix}level* 905 | Check your level. 906 | Aliases: - 907 | Usage: *${prefix}level* 908 | 909 | 2. *${prefix}leaderboard* 910 | Check leaderboard. 911 | Aliaases: - 912 | Usage: *${prefix}leaderboard* 913 | 914 | _Index of [9]_ 915 | ` 916 | } 917 | 918 | exports.menuAi = () => { 919 | return ` 920 | *── 「 AI 」 ──* 921 | 922 | 1. *${prefix}ai* 923 | ChatGPT 3.5 implementation. 924 | Aliases: - 925 | Usage: *${prefix}ai* your_question 926 | 927 | 2. *${prefix}image* 928 | Create image from given prompt. 929 | Aliases: *img* 930 | Usage: *${prefix}image* prompt 931 | 932 | _Index of [10]_ 933 | ` 934 | } 935 | 936 | exports.rules = () => { 937 | return ` 938 | *── 「 RULES 」 ──* 939 | 940 | 1. Do NOT spam bot. 941 | Penalty: *WARN/SOFT BLOCK* 942 | 943 | 2. Do NOT call bot. 944 | Penalty: *SOFT BLOCK* 945 | 946 | 3. Do NOT exploit bots. 947 | Penalty: *PERMANENT BLOCK* 948 | 949 | If you've understand these rules, please type *${prefix}menu* to get started. 950 | ` 951 | } 952 | 953 | // Note for owner/hoster, please DO NOT edit this section. 954 | exports.tos = (ownerNumber) => { 955 | return ` 956 | *── 「 TERMS OF SERVICE 」 ──* 957 | 958 | This bot is an open-source bot, come with the name of BocchiBot which is available on GitHub for free. 959 | The owner/hoster of this bot is independent from the responsibility and supervision of the developer (Slavyan). 960 | Owner/hoster may plagiarize, add, delete, replace source code with notes *DO NOT SELL* this source code in any form. 961 | If an error occurs, the first person you should contact is the owner/hoster. 962 | 963 | If you want to contributing to this project, visit: 964 | https://github.com/SlavyanDesu/BocchiBot 965 | 966 | Contact person: 967 | wa.me/${ownerNumber.replace('@c.us', '')} (Owner/hoster) 968 | 969 | Regards, 970 | Slavyan 971 | ` 972 | } 973 | -------------------------------------------------------------------------------- /message/text/lang/ind.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable quotes */ 2 | const { prefix } = require('../../../config.json') 3 | 4 | exports.wait = () => { 5 | return `Mohon tunggu sebentar...` 6 | } 7 | 8 | exports.ok = () => { 9 | return `Done!` 10 | } 11 | 12 | exports.videoLimit = () => { 13 | return `Ukuran video/GIF terlalu besar!` 14 | } 15 | 16 | exports.wrongFormat = () => { 17 | return `Format salah! Silakan cek cara penggunaan di *${prefix}menu*.` 18 | } 19 | 20 | exports.emptyMess = () => { 21 | return `Harap masukkan pesan yang ingin disampaikan!` 22 | } 23 | 24 | exports.cmdNotFound = (cmd) => { 25 | return `Command *${prefix}${cmd}* tidak ditemukan!` 26 | } 27 | 28 | exports.blocked = (ownerNumber) => { 29 | return `Bot tidak menerima panggilan. Kamu diblokir karena telah melanggar rules!\n\nHubungi owner: wa.me/${ownerNumber.replace('@c.us', '')}` 30 | } 31 | 32 | exports.ownerOnly = () => { 33 | return `Command ini hanya bisa digunakan oleh owner!` 34 | } 35 | 36 | exports.groupOnly = () => { 37 | return `Command ini hanya bisa digunakan di dalam grup!` 38 | } 39 | 40 | exports.adminOnly = () => { 41 | return `Command ini hanya bisa digunakan oleh admin grup!` 42 | } 43 | 44 | exports.addedGroup = (chat) => { 45 | return `Terima kasih telah mengundangku, para member *${chat.contact.name}*!\n\nSilakan register di *private chat* dengan format:\n*${prefix}register* nama` 46 | } 47 | 48 | exports.listBlock = (blockNumber) => { 49 | return ` 50 | *── 「 HALL OF SHAME 」 ──* 51 | 52 | Total user diblokir: *${blockNumber.length}*\n 53 | ` 54 | } 55 | 56 | exports.notPremium = () => { 57 | return `Maaf! Command ini khusus untuk user premium saja.` 58 | } 59 | 60 | exports.notAdmin = () => { 61 | return `User bukan seorang admin!` 62 | } 63 | 64 | exports.adminAlready = () => { 65 | return `Tidak dapat mem-promote user yang merupakan admin!` 66 | } 67 | 68 | exports.botNotPremium = () => { 69 | return `Bot ini tidak mendukung command premium. Silakan hubungi pemilik bot ini.` 70 | } 71 | 72 | exports.botNotAdmin = () => { 73 | return `Jadikan bot sebagai admin terlebih dahulu!` 74 | } 75 | 76 | exports.notRegistered = () => { 77 | return `Kamu belum terdaftar di database!\n\nSilakan register di *private chat* dengan format:\n*${prefix}register* nama` 78 | } 79 | 80 | exports.registered = (name, userId, time, serial) => { 81 | return ` 82 | *── 「 REGISTRATION 」 ──* 83 | 84 | Akun kamu telah terdaftar dengan data: 85 | ➸ *Nama*: ${name} 86 | ➸ *ID*: ${userId} 87 | ➸ *Waktu pendaftaran*: ${time} 88 | ➸ *Serial*: ${serial} 89 | 90 | Catatan: 91 | Jangan pernah menyebarkan data *serial* ke pada siapapun! 92 | 93 | Ketik *${prefix}rules* terlebih dahulu ya~ 94 | ` 95 | } 96 | 97 | exports.registeredAlready = () => { 98 | return `Kamu sudah mendaftar sebelumnya.` 99 | } 100 | 101 | exports.received = (pushname) => { 102 | return `Halo ${pushname}!\nTerima kasih telah melapor, laporanmu akan kami segera terima.` 103 | } 104 | 105 | exports.daily = (time) => { 106 | return `Maaf, tetapi kamu telah mencapai limit menggunakan command ini.\nSilakan tunggu *${time.hours}* jam *${time.minutes}* menit *${time.seconds}* detik lagi.` 107 | } 108 | 109 | exports.profile = (username, status, premi, benet, adm, level, requiredXp, xp) => { 110 | return ` 111 | *── 「 USER INFO」 ──* 112 | 113 | ➸ *Username*: ${username} 114 | ➸ *Status*: ${status} 115 | ➸ *Premium*: ${premi} 116 | ➸ *Banned*: ${benet} 117 | ➸ *Admin*: ${adm} 118 | 119 | =_=_=_=_=_=_=_=_=_=_=_=_= 120 | 121 | *── 「 PROGRESS 」 ──* 122 | 123 | ➸ *Level*: ${level} 124 | ➸ *XP*: ${xp} / ${requiredXp} 125 | ` 126 | } 127 | 128 | exports.detectorOn = (name, formattedTitle) => { 129 | return ` 130 | *── 「 ANTI GROUP LINK 」 ──* 131 | 132 | Pengumuman untuk member *${(name || formattedTitle)}*. 133 | Grup ini memiliki group link detector, apabila ada member yang mengirim group link, maka dia akan ter-kick secara otomatis. 134 | 135 | Sekian terima kasih. 136 | - Admin *${(name || formattedTitle)}* 137 | ` 138 | } 139 | 140 | exports.linkDetected = () => { 141 | return ` 142 | *── 「 ANTI GROUP LINK 」 ──* 143 | 144 | Kamu mengirim link group chat! 145 | Maaf tapi kamu harus keluar... 146 | ` 147 | } 148 | 149 | exports.detectorOff = () => { 150 | return `Fitur anti-group link berhasil *dinonaktifkan*!` 151 | } 152 | 153 | exports.detectorOnAlready = () => { 154 | return `Fitur anti-group link telah diaktifkan sebelumnya.` 155 | } 156 | 157 | exports.antiNsfwOn = (name, formattedTitle) => { 158 | return ` 159 | *── 「 ANTI NSFW LINK 」 ──* 160 | 161 | Pengumuman untuk member *${(name || formattedTitle)}*. 162 | Grup ini memiliki NSFW link detector, apabila ada member yang mengirim NSFW link, maka dia akan ter-kick secara otomatis. 163 | 164 | Sekian terima kasih. 165 | - Admin *${(name || formattedTitle)}* 166 | ` 167 | } 168 | 169 | exports.antiNsfwOff = () => { 170 | return `Fitur anti-NSFW link berhasil *dinonaktifkan*!` 171 | } 172 | 173 | exports.antiNsfwOnAlready = () => { 174 | return `Fitur anti-NSFW link telah diaktifkan sebelumnya.` 175 | } 176 | 177 | exports.antiBadWordsOn = (name, formattedTitle) => { 178 | return ` 179 | *── 「 ANTI BAD WORDS 」 ──* 180 | 181 | Pengumuman untuk member *${(name || formattedTitle)}*. 182 | Grup ini memiliki bad word detector, apabila ada member yang mengirim bad word/kata kasar, maka pesannya akan segera dihapus. 183 | 184 | Sekian terima kasih. 185 | - Admin *${(name || formattedTitle)}* 186 | ` 187 | } 188 | 189 | exports.antiBadWordsOff = () => { 190 | return `Fitur anti-bad word berhasil *dinonaktifkan*!` 191 | } 192 | 193 | exports.antiBadWordsOnAlready = () => { 194 | return `Fitur anti-bad word telah diaktifkan sebelumnya.` 195 | } 196 | 197 | exports.antiBadWordsError = () => { 198 | return `Fitur anti-bad word belum diaktifkan!` 199 | } 200 | 201 | exports.levelingOn = () => { 202 | return `Fitur leveling berhasil *diaktifkan*!` 203 | } 204 | 205 | exports.levelingOff = () => { 206 | return `Fitur leveling berhasil *dinonaktifkan*!` 207 | } 208 | 209 | exports.levelingOnAlready = () => { 210 | return `Fitur leveling telah diaktifkan sebelumnya.` 211 | } 212 | 213 | exports.levelingNotOn = () => { 214 | return `Fitur leveling belum diaktifkan!` 215 | } 216 | 217 | exports.levelNull = () => { 218 | return `Kamu belum memiliki level!` 219 | } 220 | 221 | exports.welcome = (event) => { 222 | return `Selamat datang @${event.who.replace('@c.us', '')}!` 223 | } 224 | 225 | exports.welcomeOn = () => { 226 | return `Fitur welcome berhasil *diaktifkan*!` 227 | } 228 | 229 | exports.welcomeOff = () => { 230 | return `Fitur welcome berhasil *dinonaktifkan*!` 231 | } 232 | 233 | exports.welcomeOnAlready = () => { 234 | return `Fitur welcome telah diaktifkan sebelumnya.` 235 | } 236 | 237 | exports.minimalDb = () => { 238 | return `Perlu setidaknya *10* user yang memiliki level di database!` 239 | } 240 | 241 | exports.autoStikOn = () => { 242 | return `Fitur auto-stiker berhasil *diaktifkan*!` 243 | } 244 | 245 | exports.autoStikOff = () => { 246 | return `Fitur auto-stiker berhasil *dinonaktifkan*!` 247 | } 248 | 249 | exports.autoStikOnAlready = () => { 250 | return `Fitur auto-stiker telah diaktifkan sebelumnya.` 251 | } 252 | 253 | exports.afkOn = (pushname, reason) => { 254 | return ` 255 | *── 「 AFK MODE 」 ──* 256 | 257 | Fitur AFK berhasil *diaktifkan*! 258 | ➸ *Username*: ${pushname} 259 | ➸ *Alasan*: ${reason} 260 | ` 261 | } 262 | 263 | exports.afkOnAlready = () => { 264 | return `Fitur AFK telah diaktifkan sebelumnya.` 265 | } 266 | 267 | exports.afkMentioned = (getReason, getTime) => { 268 | return ` 269 | *── 「 AFK MODE 」 ──* 270 | 271 | Sssttt! Orangnya lagi AFK, jangan diganggu! 272 | ➸ *Alasan*: ${getReason} 273 | ➸ *Sejak*: ${getTime} 274 | ` 275 | } 276 | 277 | exports.afkDone = (pushname) => { 278 | return `*${pushname}* telah kembali dari AFK! Selamat datang kembali~` 279 | } 280 | 281 | exports.gcMute = () => { 282 | return ` 283 | *── 「 MUTED 」 ──* 284 | 285 | Hanya admin yang dapat mengirim pesan ke grup ini. 286 | ` 287 | } 288 | 289 | exports.gcUnmute = () => { 290 | return ` 291 | *── 「 UNMUTED 」 ──* 292 | 293 | Sekarang semua anggota dapat mengirim chat di grup ini. 294 | ` 295 | } 296 | 297 | exports.notNum = (q) => { 298 | return `"${q}", bukan angka!` 299 | } 300 | 301 | exports.registeredFound = (name, time, serial, userId) => { 302 | return ` 303 | *── 「 REGISTERED 」 ──* 304 | 305 | Akun ditemukan! 306 | ➸ *Nama*: ${name} 307 | ➸ *ID*: ${userId} 308 | ➸ *Waktu pendaftaran*: ${time} 309 | ➸ *Serial*: ${serial} 310 | ` 311 | } 312 | 313 | exports.registeredNotFound = (serial) => { 314 | return `Akun dengan serial: *${serial}* tidak ditemukan!` 315 | } 316 | 317 | exports.pcOnly = () => { 318 | return `Command ini hanya bisa digunakan di dalam private chat saja!` 319 | } 320 | 321 | exports.linkNsfw = () => { 322 | return ` 323 | *── 「 ANTI NSFW LINK 」 ──* 324 | 325 | Kamu telah mengirim link NSFW! 326 | Maaf, tapi aku harus mengeluarkan mu... 327 | ` 328 | } 329 | 330 | exports.fakeLink = () => { 331 | return `Ups, link ini terlihat mencurigakan. Demi keamanan grup, aku harus mengeluarkan mu...\n` 332 | } 333 | 334 | exports.muteChatOn = () => { 335 | return `Berhasil *mute* bot pada grup ini!` 336 | } 337 | 338 | exports.muteChatOff = () => { 339 | return `Berhasil *unmute* bot pada grup ini!` 340 | } 341 | 342 | exports.muteChatOnAlready = () => { 343 | return `Mute telah diaktifkan di grup ini sebelumnya!` 344 | } 345 | 346 | exports.limit = () => { 347 | return ` 348 | *── 「 LIMIT 」 ──* 349 | 350 | Limit penggunaan kamu telah habis! Silakan lakukan hal berikut: 351 | ❏ *_Tunggu hingga jam 00:00 WIB_* 352 | ` 353 | } 354 | 355 | exports.reminderOn = (messRemind, parsedTime, sender) => { 356 | return ` 357 | *── 「 REMINDER 」 ──* 358 | 359 | Reminder berhasil diaktifkan! 360 | ➸ *Pesan*: ${messRemind} 361 | ➸ *Durasi*: ${parsedTime.hours} jam ${parsedTime.minutes} menit ${parsedTime.seconds} detik 362 | ➸ *Untuk*: @${sender.id.replace('@c.us', '')} 363 | ` 364 | } 365 | 366 | exports.reminderAlert = (messRemind, sender) => { 367 | return ` 368 | *── 「 REMINDER 」 ──* 369 | 370 | ⏰ @${sender.id.replace('@c.us', '')} ⏰ 371 | ➸ *Pesan*: ${messRemind}` 372 | } 373 | 374 | exports.nameChanged = (q) => { 375 | return `Username berhasil diubah ke *${q}*` 376 | } 377 | 378 | exports.menu = (jumlahUser, level, xp, role, pushname, requiredXp, premium) => { 379 | return ` 380 | *── 「 WELCOME 」 ──* 381 | 382 | ====================== 383 | ➸ *Nama*: ${pushname} 384 | ➸ *Level*: ${level} 385 | ➸ *XP*: ${xp} / ${requiredXp} 386 | ➸ *Role*: ${role} 387 | ➸ *Premium*: ${premium} 388 | ====================== 389 | 390 | Total pendaftar: *${jumlahUser}* 391 | 392 | Berikut adalah menu yang tersedia: 393 | 394 | *[1]* Downloader 395 | *[2]* Bot 396 | *[3]* Misc 397 | *[4]* Sticker 398 | *[5]* Weeaboo 399 | *[6]* Fun 400 | *[7]* Moderation 401 | *[8]* Owner 402 | *[9]* Leveling 403 | *[10]* AI 404 | 405 | Ketik *${prefix}menu* angka_index untuk membuka menu page yang dipilih. 406 | 407 | Catatan: 408 | Bot ini terdapat cooldown command selama *5 detik* setiap kali pemakaian. 409 | ` 410 | } 411 | 412 | exports.menuDownloader = () => { 413 | return ` 414 | *── 「 DOWNLOADER 」 ──* 415 | 416 | 1. *${prefix}twitter* 417 | Download Twitter media. 418 | Aliases: *twt* 419 | Usage: *${prefix}twitter* link 420 | 421 | 2. *${prefix}youtube* 422 | Download YouTube video. 423 | Aliases: *yt* 424 | Usage: *${prefix}youtube* link 425 | 426 | _Index of [1]_ 427 | ` 428 | } 429 | 430 | exports.menuBot = () => { 431 | return ` 432 | *── 「 BOT 」 ──* 433 | 434 | 1. *${prefix}rules* 435 | Wajib baca. 436 | Aliases: *rule* 437 | Usage: *${prefix}rules* 438 | 439 | 2. *${prefix}menu* 440 | Menampilkan commands yang tersedia. 441 | Aliases: *help* 442 | Usage: *${prefix}menu* angka_index 443 | 444 | 3. *${prefix}status* 445 | Menampilkan status bot. 446 | Aliases: *stats* 447 | Usage: *${prefix}status* 448 | 449 | 4. *${prefix}listblock* 450 | Cek nomor yang diblokir. 451 | Aliases: - 452 | Usage: *${prefix}listblock* 453 | 454 | 5. *${prefix}ping* 455 | Cek speed bot. 456 | Aliases: *p* 457 | Usage: *${prefix}ping* 458 | 459 | 6. *${prefix}delete* 460 | Hapus pesan dari bot. 461 | Aliases: *del* 462 | Usage: Reply pesan yang dihapus dengan caption *${prefix}delete*. 463 | 464 | 7. *${prefix}report* 465 | Laporkan bug ke dev. 466 | Aliases: - 467 | Usage: *${prefix}report* pesan 468 | 469 | 8. *${prefix}tos* 470 | Syarat dan ketentuan. (TOS) 471 | Aliases: - 472 | Usage: *${prefix}tos* 473 | 474 | 9. *${prefix}join* 475 | Join grup via link. 476 | Aliases: - 477 | Usage: *${prefix}join* link_group 478 | 479 | 10. *${prefix}ownerbot* 480 | Mengirim kontak owner. 481 | Aliases: - 482 | Usage: *${prefix}ownerbot* 483 | 484 | 11. *${prefix}getpic* 485 | Mengirim foto profil user. 486 | Aliases: - 487 | Usage: *${prefix}getpic* @user/62812xxxxxxxx 488 | 489 | 12. *${prefix}premiumcheck* 490 | Cek masa aktif premium. 491 | Aliases: *cekpremium* 492 | Usage: *${prefix}premiumcheck* 493 | 494 | 13. *${prefix}premiumlist* 495 | Cek list user premium. 496 | Aliases: *listpremium* 497 | Usage: *${prefix}premiumlist* 498 | 499 | 14. *${prefix}limit* 500 | Cek limit kamu. 501 | Aliases: - 502 | Usage: *${prefix}limit* 503 | 504 | 15. *${prefix}serial* 505 | Cek biodata menggunakan serial. 506 | Aliases: - 507 | Usage: *${prefix}serial* serial 508 | 509 | 16. *${prefix}runtime* 510 | Cek runtime host. 511 | Aliases: - 512 | Usage: *${prefix}runtime* 513 | 514 | 17. *${prefix}unregister* 515 | Unregister akun. 516 | Aliases: *unreg* 517 | Usage: *${prefix}unregister* 518 | 519 | _Index of [2]_ 520 | ` 521 | } 522 | 523 | exports.menuMisc = () => { 524 | return ` 525 | *── 「 MISC 」 ──* 526 | 527 | 1. *${prefix}say* 528 | Bot akan mengulang pesan mu. 529 | Aliases: - 530 | Usage: *${prefix}say* teks 531 | 532 | 2. *${prefix}tts* 533 | Membuat Text to Speech. Kalian perlu kode bahasa setiap menggunakan, cek di sini https://id.wikipedia.org/wiki/Daftar_bahasa_menurut_ISO_639-2 534 | Aliases: - 535 | Usage: *${prefix}tts* kode_bahasa | teks 536 | 537 | 3. *${prefix}afk* 538 | Set akun kamu ke mode AFK, aku akan mengirim pesan ke orang yang me-mention kamu. 539 | Aliases: - 540 | Usage: *${prefix}afk* alasan. Kirim pesan ke grup untuk menonaktifkan mode AFK. 541 | 542 | 4. *${prefix}math* 543 | Kalkulator. 544 | * = Perkalian 545 | + = Pertambahan 546 | - = Pengurangan 547 | / = Pembagian 548 | Aliases: - 549 | Usage: *${prefix}math* 12*12 550 | 551 | 5. *${prefix}reminder* 552 | Pengingat. 553 | *s* - detik 554 | *m* - menit 555 | *h* - jam 556 | *d* - hari 557 | Aliases: - 558 | Usage: *${prefix}reminder* 10s | pesan_pengingat 559 | 560 | 6. *${prefix}imagetourl* 561 | Image uploader. 562 | Aliases: *imgtourl* 563 | Usage: Kirim gambar dengan caption *${prefix}imagetourl* atau reply gambar dengan caption *${prefix}imagetourl*. 564 | 565 | 7. *${prefix}genshininfo* 566 | Kirim info karakter Genshin Impact. 567 | Aliases: *genshin* 568 | Usage: *${prefix}genshininfo* nama_karakter 569 | 570 | 8. *${prefix}translate* 571 | Terjemahkan teks. 572 | Aliases: *trans* 573 | Usage: *${prefix}translate* teks | kode_bahasa, bisa menggunakan reply juga 574 | 575 | 9. *${prefix}tomp3* 576 | Format video ke MP3. 577 | Aliases: - 578 | Usage: Kirim video dengan caption *${prefix}tomp3* atau reply video dengan caption *${prefix}tomp3*. 579 | 580 | 10. *${prefix}bass* 581 | Bass boost, bikin telinga sakit. 582 | Aliases: - 583 | Usage: Reply audio/voice dengan caption *${prefix}bass* tingkat_dB. 584 | 585 | 11. *${prefix}nightcore* 586 | Membuat efek nightcore dari audio. 587 | Aliases: - 588 | Usage: Reply audio/voice dengan caption *${prefix}nightcore* 589 | 590 | 12. *${prefix}google* 591 | Mencari via Google. 592 | Aliases: *googlesearch* 593 | Usage: *${prefix}google* query 594 | 595 | 13. *${prefix}toptt* 596 | Buat audio PTT. 597 | Aliases: *ptt* 598 | Usage: Reply audio/voice dengan caption *${prefix}toptt* 599 | 600 | 14. *${prefix}quizizz* 601 | Mengambil Data Quizizz 602 | Aliases: *quizizz hack* 603 | Usage: *${prefix}quizizz* query 604 | 605 | 606 | _Index of [3]_ 607 | ` 608 | } 609 | 610 | exports.menuSticker = () => { 611 | return ` 612 | *── 「 STICKER 」 ──* 613 | 614 | 1. *${prefix}sticker* 615 | Membuat stiker dari gambar yang dikirim atau di-reply. 616 | Aliases: *stiker* 617 | Usage: Kirim gambar dengan caption *${prefix}sticker* atau reply gambar dengan caption *${prefix}sticker*. 618 | 619 | 2. *${prefix}stickergif* 620 | Membuat stiker dari video MP4 atau GIF yang dikirim atau di-reply. 621 | Aliases: *stikergif* 622 | Usage: Kirim video/GIF dengan caption *${prefix}stickergif* atau reply video/GIF dengan caption *${prefix}stickergif*. 623 | 624 | 3. *${prefix}stickertoimg* 625 | Konversi stiker ke foto. 626 | Aliases: *stikertoimg toimg* 627 | Usage: Reply sticker dengan caption *${prefix}stickertoimg*. 628 | 629 | 4. *${prefix}stickerwm* 630 | Buat stiker dengan WM. 631 | Aliases: *stcwm* 632 | Usage: Kirim gambar dengan caption *${prefix}stickerwm* pack_name | author_name atau reply gambar dengan caption *${prefix}stickerwm* pack_name | author_name. 633 | 634 | 5. *${prefix}stickermeme* 635 | Buat sticker meme. 636 | Aliases: *stcmeme* 637 | Usage: Kirim gambar dengan caption *${prefix}stickermeme* teks_atas | teks_bawah atau reply gambar dengan caption *${prefix}stickermeme* teks_atas | teks_bawah. 638 | 639 | 6. *${prefix}takestick* 640 | Merubah watermark sticker. 641 | Aliases: - 642 | Usage: Reply stiker dengan caption *${prefix}takestick* pack_name | author_name 643 | 644 | 7. *${prefix}stickernobg* 645 | Membuat stiker tanpa background. 646 | Aliases: *take* 647 | Usage: Kirim gambar dengan caption *${prefix}stickernobg* atau reply gambar dengan caption *${prefix}stickernobg* 648 | 649 | 650 | _Index of [4]_ 651 | ` 652 | } 653 | 654 | exports.menuWeeaboo = () => { 655 | return ` 656 | *── 「 WEEABOO 」 ──* 657 | 658 | 1. *${prefix}neko* 659 | Mengirim foto neko girl. 660 | Aliases: - 661 | Usage: *${prefix}neko* 662 | 663 | 2. *${prefix}wallpaper* 664 | Mengirim wallpaper anime. 665 | Aliases: *wp* 666 | Usage: *${prefix}wallpaper* 667 | 668 | 3. *${prefix}kemono* 669 | Mengirim foto kemonomimi girl. 670 | Aliases: - 671 | Usage: *${prefix}kemono* 672 | 673 | 4. *${prefix}wait* 674 | Mencari source anime dari screenshot scene. 675 | Aliases: - 676 | Usage: Kirim screenshot dengan caption *${prefix}wait* atau reply screenshot dengan caption *${prefix}wait*. 677 | 678 | 5. *${prefix}source* 679 | Mencari source dari panel doujin, ilustrasi, dan gambar yang berhubungan dengan anime. 680 | Aliases: *sauce* 681 | Usage: Kirim gambar dengan caption *${prefix}source* atau reply gambar dengan caption *${prefix}source*. 682 | 683 | 6. *${prefix}waifu* 684 | Mengirim random foto waifu. 685 | Aliases: - 686 | Usage: *${prefix}waifu* 687 | 688 | _Index of [5]_ 689 | ` 690 | } 691 | 692 | exports.menuFun = () => { 693 | return ` 694 | *── 「 FUN 」 ──* 695 | 696 | 1. *${prefix}triggered* 697 | Membuat efek triggered. 698 | Aliases: - 699 | Usage: Kirim gambar dengan caption *${prefix}triggered* atau reply pesan orang dengan *${prefix}triggered*. 700 | 701 | 2. *${prefix}kiss* 702 | Kiss someone ( ͡° ͜ʖ ͡°). 703 | Aliases: - 704 | Usage: Kirim gambar dengan caption *${prefix}kiss* atau reply gambar dengan *${prefix}kiss*. 705 | 706 | 3. *${prefix}profile* 707 | Cek profile. 708 | Aliases: *me* 709 | Usage: *${prefix}profile* 710 | 711 | 4. *${prefix}trash* 712 | Trash? 713 | Aliases: - 714 | Usage: *${prefix}trash* 715 | 716 | 5. *${prefix}hitler* 717 | Worse than hitler. 718 | Aliases: - 719 | Usage: *${prefix}hitler* 720 | 721 | _Index of [6]_ 722 | ` 723 | } 724 | 725 | exports.menuModeration = () => { 726 | return ` 727 | *── 「 MODERATION 」 ──* 728 | 729 | 1. *${prefix}add* 730 | Menambah user ke dalam group. 731 | Aliases: - 732 | Usage: *${prefix}add* 628xxxxxxxxxx 733 | 734 | 2. *${prefix}kick* 735 | Mengeluarkan member dari grup. 736 | Aliases: - 737 | Usage: *${prefix}kick* @member1 738 | 739 | 3. *${prefix}promote* 740 | Promote member menjadi admin. 741 | Aliases: - 742 | Usage: *${prefix}promote* @member1 743 | 744 | 4. *${prefix}demote* 745 | Demote member dari admin. 746 | Aliases: - 747 | Usage: *${prefix}demote* @member1 748 | 749 | 5. *${prefix}leave* 750 | Bot akan meninggalkan grup. 751 | Aliases: - 752 | Usage: *${prefix}leave* 753 | 754 | 6. *${prefix}everyone* 755 | Mention semua member group. 756 | Aliases: - 757 | Usage: *${prefix}everyone* 758 | 759 | 7. *${prefix}groupicon* 760 | Mengganti icon grup. 761 | Aliases: - 762 | Usage: Kirim gambar dengan caption *${prefix}groupicon* atau reply gambar dengan caption *${prefix}groupicon*. 763 | 764 | 8. *${prefix}antilink* 765 | Mematikan/menyalakan fitur anti-group link. 766 | Aliases: - 767 | Usage: *${prefix}antilink* enable/disable 768 | 769 | 9. *${prefix}welcome* 770 | Mematikan/menyalakan fitur welcome di grup agar menyambut setiap kedatangan member. 771 | Aliases: - 772 | Usage: *${prefix}welcome* enable/disable 773 | 774 | 10. *${prefix}autosticker* 775 | Mematikan/menyalakan fitur auto-stiker. Setiap foto yang dikirim akan selalu diubah ke stiker. 776 | Aliases: *autostiker autostik* 777 | Usage: *${prefix}autostiker* enable/disable 778 | 779 | 11. *${prefix}antinsfw* 780 | Mematikan/menyalakan fitur anti-NSFW link. 781 | Aliases: - 782 | Usage: *${prefix}antinsfw* enable/disable 783 | 784 | 12. *${prefix}mutegc* 785 | Set group hanya admin yang bisa mengirim pesan. 786 | Aliases: - 787 | Usage: *${prefix}mutegc* enabled/disable 788 | 789 | 13. *${prefix}grouplink* 790 | Melihat invite link grup. 791 | Aliases: - 792 | Usage: *${prefix}grouplink* 793 | 794 | 14. *${prefix}revoke* 795 | Revoke invite link grup. 796 | Aliases: - 797 | Usage: *${prefix}revoke* 798 | 799 | 15. *${prefix}leveling* 800 | Mematikan/menyalakan fitur leveling. 801 | Aliases: - 802 | Usage: *${prefix}leveling* enable/disable 803 | 804 | 16. *${prefix}badwords* 805 | Setting fitur anti-bad word. 806 | Aliases: *badword* 807 | Usage: *${prefix}badwords* enable/disable atau add/remove untuk menambahkan/menghapus kata kasar. 808 | 809 | 810 | _Index of [7]_ 811 | ` 812 | } 813 | 814 | exports.menuOwner = () => { 815 | return ` 816 | *── 「 OWNER 」 ──* 817 | 818 | 1. *${prefix}bc* 819 | Membuat broadcast. 820 | Aliases: - 821 | Usage: *${prefix}bc* teks 822 | 823 | 2. *${prefix}clearall* 824 | Menghapus semua chat di akun bot. 825 | Aliases: - 826 | Usage: *${prefix}clearall* 827 | 828 | 3. *${prefix}getses* 829 | Mengambil screenshot sesi dari akun bot. 830 | Aliases: - 831 | Usage: *${prefix}getses* 832 | 833 | 4. *${prefix}ban* 834 | Menambah/menghapus user yang diban. 835 | Aliases: - 836 | Usage: *${prefix}ban* add/del @user/62812xxxxxxxx 837 | 838 | 5. *${prefix}leaveall* 839 | Keluar dari semua grup. 840 | Aliases: - 841 | Usage: *${prefix}leaveall* 842 | 843 | 6. *${prefix}eval* 844 | Evaluate kode JavaScript. 845 | Aliases: *ev* 846 | Usage: *${prefix}eval* 847 | 848 | 7. *${prefix}shutdown* 849 | Men-shutdown bot. 850 | Aliases: - 851 | Usage: *${prefix}shutdown* 852 | 853 | 8. *${prefix}premium* 854 | Menambah/menghapus user premium. 855 | *s* - detik 856 | *m* - menit 857 | *h* - jam 858 | *d* - hari 859 | Aliases: - 860 | Usage: *${prefix}premium* add/del @user/62812xxxxxxxx 30d 861 | 862 | 9. *${prefix}setstatus* 863 | Mengganti status about me. 864 | Aliases: *setstats setstat* 865 | Usage: *${prefix}status* teks 866 | 867 | 10. *${prefix}serial* 868 | Cek pendaftaran akun via serial. 869 | Aliases: - 870 | Usage: *${prefix}serial* serial_user 871 | 872 | 11. *${prefix}exif* 873 | Atur WM stiker bot. 874 | Aliases: - 875 | Usage: *${prefix}exif* pack_name | author_name 876 | 877 | 12. *${prefix}mute* 878 | Mute semua user. 879 | Aliases: - 880 | Usage: Gunakan *${prefix}mute* untuk mute dan gunakan *${prefix}mute* kembali untuk unmute. 881 | 882 | 13. *${prefix}setname* 883 | Mengganti username bot. Maksimal 25 huruf. 884 | Aliases: - 885 | Usage: *${prefix}name* username_baru 886 | 887 | 14. *${prefix}block* 888 | Blok user. 889 | Aliases: *blok* 890 | Usage: *${prefix}block* @user/62812xxxxxxxx 891 | 892 | 15. *${prefix}unblock* 893 | Unblok user. 894 | Aliases: *unblok* 895 | Usage: *${prefix}unblock* @user/62812xxxxxxxx 896 | 897 | 16. *${prefix}xp* 898 | Menambahkan XP ke user. 899 | Aliases: - 900 | Usage: *${prefix}xp* @user jumlah_xp 901 | 902 | _Index of [8]_ 903 | ` 904 | } 905 | 906 | exports.menuLeveling = () => { 907 | return ` 908 | *── 「 LEVELING 」 ──* 909 | 910 | 1. *${prefix}level* 911 | Untuk melihat level kamu. 912 | Aliases: - 913 | Usage: *${prefix}level* 914 | 915 | 2. *${prefix}leaderboard* 916 | Untuk melihat leaderboard. 917 | Aliaases: - 918 | Usage: *${prefix}leaderboard* 919 | 920 | _Index of [9]_ 921 | ` 922 | } 923 | 924 | exports.menuAi = () => { 925 | return ` 926 | *── 「 AI 」 ──* 927 | 928 | 1. *${prefix}ai* 929 | Implementasi untuk ChatGPT 3.5 930 | Aliases: - 931 | Usage: *${prefix}ai* pertanyaan 932 | 933 | 2. *${prefix}image* 934 | Membuat gambar dari prompt/kata kunci. 935 | Aliases: *img* 936 | Usage: *${prefix}image* prompt 937 | 938 | _Index of [10]_ 939 | ` 940 | } 941 | 942 | exports.rules = () => { 943 | return ` 944 | *── 「 RULES 」 ──* 945 | 946 | 1. Jangan spam bot. 947 | Sanksi: *WARN/SOFT BLOCK* 948 | 949 | 2. Jangan telepon bot. 950 | Sanksi: *SOFT BLOCK* 951 | 952 | 3. Jangan mengeksploitasi bot. 953 | Sanksi: *PERMANENT BLOCK* 954 | 955 | Jika sudah dipahami rules-nya, silakan ketik *${prefix}menu* untuk memulai! 956 | ` 957 | } 958 | 959 | // Dimohon untuk owner/hoster jangan mengedit ini, terima kasih. 960 | exports.tos = (ownerNumber) => { 961 | return ` 962 | *── 「 TERMS OF SERVICE 」 ──* 963 | 964 | Bot ini merupakan open-source bot dengan nama asli BocchiBot yang tersedia di GitHub secara gratis. 965 | Owner/hoster dari bot ini terlepas dari tanggung jawab dan pengawasan developer (Slavyan). 966 | Owner/hoster boleh menjiplak, menambahkan, menghapus, mengganti source code dengan catatan *tidak memperjualbelikannya* dalam bentuk apapun. 967 | Apabila terjadi sebuah error, orang yang pertama yang harus kalian hubungi ialah owner/hoster. 968 | 969 | Jika kalian ingin berkontribusi dalam projek ini, silakan kunjungi: 970 | https://github.com/SlavyanDesu/BocchiBot 971 | 972 | Contact person: 973 | wa.me/${ownerNumber.replace('@c.us', '')} (Owner/hoster) 974 | 975 | Regards, 976 | Slavyan. 977 | ` 978 | } 979 | -------------------------------------------------------------------------------- /message/text/lang/index.js: -------------------------------------------------------------------------------- 1 | exports.ind = require('./ind') 2 | exports.eng = require('./eng') -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bocchibot", 3 | "version": "1.5.0", 4 | "description": "BocchiBot is a multipurpose WhatsApp bot.", 5 | "main": "index.js", 6 | "type": "commonjs", 7 | "scripts": { 8 | "start": "node index.js" 9 | }, 10 | "author": "SlavyanDesu", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/SlavyanDesu/BocchiBot.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/SlavyanDesu/BocchiBot/issues" 17 | }, 18 | "homepage": "https://github.com/SlavyanDesu/BocchiBot", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@open-wa/wa-automate": "^4.65.0", 22 | "@vitalets/google-translate-api": "^9.1.0", 23 | "await-exec": "^0.1.2", 24 | "bad-words": "^3.0.4", 25 | "canvacord": "^5.4.8", 26 | "chalk": "4.1.2", 27 | "figlet": "^1.6.0", 28 | "file-type": "16.5.4", 29 | "fluent-ffmpeg": "^2.1.2", 30 | "form-data": "^4.0.0", 31 | "fs-extra": "^11.1.1", 32 | "genshin": "^1.2.4", 33 | "google-it": "^1.6.4", 34 | "is-porn": "^0.9.0", 35 | "mathjs": "^11.8.0", 36 | "moment-timezone": "^0.5.43", 37 | "ms": "^2.1.3", 38 | "nekos.life": "^3.0.0", 39 | "node-cron": "^3.0.2", 40 | "node-fetch": "2.6.7", 41 | "node-gtts": "^2.0.2", 42 | "node-tesseract-ocr": "^2.2.1", 43 | "openai": "^3.2.1", 44 | "parse-ms": "2.1.0", 45 | "sagiri": "^3.4.0", 46 | "video-url-link": "^0.1.5", 47 | "ytdl-core": "^4.11.4" 48 | }, 49 | "devDependencies": { 50 | "eslint": "^8.38.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tools/fetcher.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-async-promise-executor */ 2 | const fs = require('fs-extra') 3 | const FormData = require('form-data') 4 | const FileType = require('file-type') 5 | const fetch = require('node-fetch') 6 | 7 | /** 8 | * Fetch JSON from URL. 9 | * @param {string} url 10 | * @param {object} [options] 11 | * @returns {Promise} 12 | */ 13 | const fetchJson = (url, options) => { 14 | return new Promise(async (resolve, reject) => { 15 | try { 16 | const response = await fetch(url, options) 17 | const json = await response.json() 18 | return resolve(json) 19 | } catch (err) { 20 | return reject(err) 21 | } 22 | }) 23 | } 24 | 25 | /** 26 | * Upload images to telegra.ph server. 27 | * @param {Buffer} buffData 28 | * @param {string} fileName 29 | * @returns {Promise} 30 | */ 31 | const uploadImages = (buffData, fileName) => { 32 | return new Promise(async (resolve, reject) => { 33 | const { fromBuffer } = FileType 34 | const type = await fromBuffer(buffData) 35 | const filePath = `temp/${fileName}.${type.ext}` 36 | fs.writeFile(filePath, buffData, { encoding: 'base64' }, (err) => { 37 | if (err) reject(err) 38 | const fileData = fs.readFileSync(filePath) 39 | const form = new FormData() 40 | form.append('file', fileData, `${fileName}.${type.ext}`) 41 | fetch('https://telegra.ph/upload', { 42 | method: 'POST', 43 | body: form 44 | }) 45 | .then((response) => response.json()) 46 | .then((result) => { 47 | if (result.error) reject(result.error) 48 | resolve('https://telegra.ph' + result[0].src) 49 | }) 50 | .then(() => fs.unlinkSync(filePath)) 51 | .catch((err) => reject(err)) 52 | }) 53 | }) 54 | } 55 | 56 | module.exports = { 57 | fetchJson, 58 | uploadImages 59 | } -------------------------------------------------------------------------------- /tools/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | const chalk = require('chalk') 3 | const crypto = require('crypto') 4 | const moment = require('moment-timezone') 5 | moment.tz.setDefault('Asia/Jakarta').locale('id') 6 | 7 | /** 8 | * Get text with color. 9 | * @param {string} text 10 | * @param {string} [color] 11 | */ 12 | const color = (text, color) => { 13 | return !color ? chalk.green(text) : chalk.keyword(color)(text) 14 | } 15 | 16 | /** 17 | * Create serial ID. 18 | * @param {number} size 19 | * @returns {string} 20 | */ 21 | const createSerial = (size) => { 22 | return crypto.randomBytes(size).toString('hex').slice(0, size) 23 | } 24 | 25 | /** 26 | * URL validator. 27 | * @param {string} url 28 | * @returns {boolean} 29 | */ 30 | const isUrl = (url) => { 31 | return url.match(new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/gi)) 32 | } 33 | 34 | /** 35 | * Get time duration. 36 | * @param {Date} timestamp 37 | * @param {Date} now 38 | * @returns {number} 39 | */ 40 | const processTime = (timestamp, now) => { 41 | return moment.duration(now - moment(timestamp * 1000)).asSeconds() 42 | } 43 | 44 | const chromeArgs = [ 45 | '--aggressive-cache-discard', 46 | '--aggressive-tab-discard', 47 | '--disable-accelerated-2d-canvas', 48 | '--disable-application-cache', 49 | '--disable-cache', 50 | '--disable-dev-shm-usage', 51 | '--disable-gpu', 52 | '--disable-offline-load-stale-cache', 53 | '--disable-setuid-sandbox', 54 | '--disable-setuid-sandbox', 55 | '--disk-cache-size=0', 56 | '--ignore-certificate-errors', 57 | '--no-first-run', 58 | '--no-sandbox', 59 | '--no-zygote' 60 | ] 61 | 62 | /** 63 | * Client options. 64 | * @param {Function} start 65 | * @returns {options} 66 | */ 67 | const options = (start) => { 68 | const options = { 69 | sessionId: 'BocchiBot', 70 | headless: "new", 71 | qrTimeout: 0, 72 | authTimeout: 0, 73 | restartOnCrash: start, 74 | cacheEnabled: false, 75 | multiDevice: true, 76 | useChrome: true, 77 | killProcessOnBrowserClose: true, 78 | throwErrorOnTosBlock: false, 79 | // chromiumArgs: chromeArgs 80 | } 81 | return options 82 | } 83 | 84 | // Anti-spam 85 | const usedCommandRecently = new Set() 86 | 87 | /** 88 | * Check is number filtered. 89 | * @param {string} from 90 | * @returns {boolean} 91 | */ 92 | const isFiltered = (from) => { 93 | return !!usedCommandRecently.has(from) 94 | } 95 | 96 | /** 97 | * Add filter to number. 98 | * @param {string} from 99 | */ 100 | const addFilter = (from) => { 101 | usedCommandRecently.add(from) 102 | setTimeout(() => { 103 | return usedCommandRecently.delete(from) 104 | }, 5000) 105 | } 106 | 107 | module.exports = { 108 | msgFilter: { 109 | isFiltered, 110 | addFilter 111 | }, 112 | color, 113 | isUrl, 114 | processTime, 115 | options, 116 | createSerial 117 | } 118 | --------------------------------------------------------------------------------