├── KALO GA DIBACA BAKAL ERROR!!!.txt ├── LICENSE ├── Procfile ├── README.md ├── WEEM SYCHYY ├── app.json ├── database ├── database.json ├── dtabasem ├── jadibot │ └── sych ├── premium.json ├── sampah │ └── ydaa ├── scommand.json ├── sewa.json ├── thumbList.json ├── totalcmd.json ├── users.json └── ©YUDA ├── index.js ├── lib ├── binary.js ├── converter.js ├── exif.js ├── function.js ├── game.js ├── math.js ├── naze.js ├── pixiv.js ├── screaper.js ├── sychyy.js ├── test ├── tictactoe.js ├── tts.js └── uploader.js ├── naze.js ├── node_modules.zip ├── package.json ├── setown.js ├── settings.js ├── speed.py ├── src ├── SYCHYY NO FES NO NEM ├── database.js ├── media │ ├── SYCHY-BOTz │ ├── fake.pdf │ ├── gmbr │ ├── stc.webp │ ├── sych.png │ └── sychy.png ├── message.js ├── nulis │ ├── font │ │ ├── Indie-Flower.ttf │ │ ├── ObelixProBIt-cyr.ttf │ │ ├── f │ │ └── impact.ttf │ ├── images │ │ ├── buku │ │ │ ├── b │ │ │ ├── sebelumkanan.jpg │ │ │ └── sebelumkiri.jpg │ │ ├── folio │ │ │ ├── f │ │ │ ├── sebelumkanan.jpg │ │ │ └── sebelumkiri.jpg │ │ └── i │ ├── nla │ └── sychyy.json ├── premium.js ├── s └── sewa.js ├── start.js ├── sychMedia ├── menu │ ├── audio.mp3 │ ├── gif.mp4 │ ├── sych.mp4 │ ├── sychy.jpg │ └── sychyy.js └── sychyy.js └── temp_image.png /KALO GA DIBACA BAKAL ERROR!!!.txt: -------------------------------------------------------------------------------- 1 | ==========================SYCHBOT============================ 2 | 3 | hellooww sebelumnya perkenalkan saya adalah yuda (ydoyy). 4 | saya sudah lama bermain bot wa, tapi sekrang sudah lupa semua :). 5 | disini saya membagikan sc no ENC apalah enc pelit banget awokwok! 6 | script nya dari king ©NAZE jangan lupa di subrek saya cuma recode aja hehe. 7 | banyak sekali bug(nguwawur bukan bug wa ya) tapi disini saya hanya ingin 8 | kalian mencoba script yang saya recode dan menambah fitur yang tentunya work ya 9 | karena saya sudah mencobanya 10 | #botwatermux ga perlu panel" an karna panel itu bayar mending yang simpel kan? 11 | lagian run bot buat diri sendiri juga kan? 12 | 13 | ======================================================== 14 | 15 | kenapa module nya dipisah? 16 | yaa karnaa ada bug kalo install langsung 17 | 18 | BACA DENGAN TELITI! 19 | $ pkg update && pkg upgrade 20 | $ pkg install git 21 | $ pkg install bash 22 | $ pkg install nodejs 23 | $ pkg install ffmpeg 24 | $ pkg install imagemagick 25 | $ pkg install libvips 26 | $ pkg install yarn 27 | $ pkg install mc 28 | $ termux-setup-storage 29 | $ cd storage 30 | $ cd downloads 31 | $ cd sych 32 | $ cp -r sych $HOME 33 | 34 | ========================================================== 35 | 36 | PERINTAH KE-2!! 37 | 38 | setelah kalian melakukan yarn dan selesai, kalian langsung ekstrak 39 | node_module.zip terserah dimana asal jangan di luar folder download 40 | nah nanti kalo pas (figlet) ada peringatan merah kalian All in aja 41 | jika sudah selesai ganti yang (sharp) jika sharp sudah selesai 42 | jangan langsung di run! 43 | kalian command ini: 44 | 45 | $ npm install --cpu=wasm32 sharp 46 | 47 | jika sudah selesai command: 48 | 49 | $ npm start 50 | 51 | nanti disuruh kasih nomer 62xxxxx dan code pairing xxXXxXX -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Naze 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 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: npm i -g pm2 && pm2 start index.js && pm2 save && pm2 logs 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Information 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | This script is created by [Nazedev](https://github.com/nazedev) using Node.js and the [WhiskeySocket/Baileys](https://github.com/WhiskeySockets/Baileys) library. The script is currently in the development phase (BETA), so there may still be some errors that can be ignored. If errors persist even after debugging, please contact the owner for assistance. ~ By Naze 14 | 15 | ## Contributor 16 | 17 | - [NazeDev](https://github.com/nazedev) (Pembuat) 18 | - [Sychyy](https://github.com/sychyy) (KangRecode) 19 | - [Zaynn](https://github.com/ZaynRcK) (Penyedia Layanan API) 20 | - [Dani](https://github.com/nazedev) (Penyumbang Code) 21 | 22 | #### Join Group 23 | [![Grup WhatsApp](https://img.shields.io/badge/WhatsApp%20Group-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/Hx9vcBVhbc04KLVGPFtH2R) 24 | 25 | --- 26 | #### Deploy to Heroku 27 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/nazedev/hitori) 28 | 29 | #### Heroku Buildpack 30 | | Build Pack | LINK | 31 | |--------|--------| 32 | | **NODEJS** | heroku/nodejs | 33 | | **FFMPEG** | [here](https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest) | 34 | | **WEBP** | [here](https://github.com/clhuang/heroku-buildpack-webp-binaries.git) | 35 | | **IMAGEMAGICK** | [here](https://github.com/DuckyTeam/heroku-buildpack-imagemagick) | 36 | 37 | --- 38 | ## For Windows/VPS/RDP User 39 | * Download And Install Git [`Click Here`](https://git-scm.com/downloads) 40 | * Download And Install NodeJS [`Click Here`](https://nodejs.org/en/download) 41 | * Download And Install FFmpeg [`Click Here`](https://ffmpeg.org/download.html) (**Don't Forget Add FFmpeg to PATH enviroment variables**) 42 | * Download And Install ImageMagick [`Click Here`](https://imagemagick.org/script/download.php) 43 | 44 | ```bash 45 | git clone https://github.com/sychyy/sychee 46 | cd sychee 47 | npm install 48 | npm update 49 | ``` 50 | --- 51 | ## For Termux/Ubuntu/SSH User 52 | ```bash 53 | pkg update && pkg upgrade 54 | pkg install git 55 | pkg install nodejs 56 | pkg install ffmpeg 57 | pkg install imagemagick 58 | pkg install libvips 59 | pkg install yarn 60 | pkg install unzip 61 | git clone https://github.com/sychyy/sychee 62 | cd sychee 63 | yarn 64 | unzip node_modules.zip 65 | npm install --cpu=wasm32 sharp 66 | npm start 67 | ``` 68 | 69 | [ RECOMMENDED INSTALL ON TERMUX ] 70 | ```bash 71 | pkg install yarn 72 | yarn 73 | ``` 74 | 75 | --- 76 | 77 | ## Ubah file simple 78 | ```bash 79 | cd sych 80 | cp ../storage/downloads/sesuain/naze.js ./naze.js 81 | ``` 82 | --- 83 | 84 | ## Agar Bot Terus Berjalan Di Termux 85 | ```bash 86 | cd sychee 87 | npm install pm2 -g 88 | pm2 start index.js -i max 89 | pm2 logs 90 | pm2 list 91 | pm2 stop index 92 | pm2 delete index 93 | pm2 restart index 94 | ``` 95 | --- 96 | ## FUNGSI PM2 97 | - lancar dan tidak mudah mati 98 | - pm2 logs (melihat logs) 99 | - pm2 list (melihat status bot) 100 | - pm2 stop index (menghentikan bot) 101 | - pm2 delete index (menghapus bot di pm2) 102 | - pm2 restart index (mulai ulang) 103 | - Ctrl + c (keluar dari logs) 104 | - clear (menghapus semua log) 105 | --- 106 | ### Connection Options 107 | - Support Qr Code 108 | - Support Pairing Code 109 | --- 110 | 111 | ### Features 112 | | Menu | Bot | Group | Search | Download | Tools | Ai | Game | Fun | Owner | 113 | | -------- | --- | ----- | ------ | -------- | ----- | -- | ---- | --- | ----- | 114 | | Work | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 115 | 116 | 117 | License: [MIT](https://choosealicense.com/licenses/mit/) 118 | 119 | #### Support Me 120 | - [Saweria](https://saweria.co/naze) 121 | 122 | ## Thanks to 123 | 124 | | [![Nazedev](https://github.com/nazedev.png?size=100)](https://github.com/nazedev) | [![Sychyy](https://github.com/sychyy.png?size=100)](https://github.com/sychyy) | [![Zaynn](https://github.com/ZaynRcK.png?size=100)](https://github.com/ZaynRcK) | [![Dani](https://github.com/nazedev.png?size=100)](https://github.com/nazedev) | [![WhiskeySockets](https://github.com/WhiskeySockets.png?size=100)](https://github.com/WhiskeySockets) | 125 | | --- | --- | --- | --- | 126 | | [NazeDev](https://github.com/nazedev) | [Sychyy](https://github.com/sychyy) | [Zaynn](https://github.com/ZaynRcK) | [Dani](https://github.com/dani) | [WhiskeySockets](https://github.com/WhiskeySockets) | 127 | -------------------------------------------------------------------------------- /WEEM SYCHYY: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hitori", 3 | "description": "WhatsApp Bot Using Lib Baileys", 4 | "repository": "https://github.com/nazedev/hitori", 5 | "logo": "https://node-js-sample.herokuapp.com/node.png", 6 | "keywords": ["multi-device"] 7 | } 8 | -------------------------------------------------------------------------------- /database/database.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /database/dtabasem: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/jadibot/sych: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/premium.json: -------------------------------------------------------------------------------- 1 | [{"id":"0@s.whatsapp.net","expired":1737086661582}] 2 | -------------------------------------------------------------------------------- /database/sampah/ydaa: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/scommand.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/sewa.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/thumbList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "sychy", 4 | "url": "https://i.ibb.co.com/kDrhMmZ/002ddb7374d40d736e9dd812645d0a2b.jpg" 5 | }, 6 | { 7 | "name": "sychyy", 8 | "url": "https://i.ibb.co.com/1QDTsvx/e7f0501e6ecdb06c6e4c05c2d7aae13d.jpg" 9 | }, 10 | { 11 | "name": "synch", 12 | "url": "https://i.ibb.co.com/K21RvZN/22d0d0f8ce1bccf9ce7185b759c32b5d.jpg" 13 | }, 14 | { 15 | "name": "sychya", 16 | "url": "https://i.ibb.co.com/85s5qjN/5cda8cf3bb0e2344cda36266673171d8.jpg" 17 | }, 18 | { 19 | "name": "synche", 20 | "url": "https://i.ibb.co.com/x6cRFN1/6cbaad220c211d8399577906a2f30856.jpg" 21 | }, 22 | { 23 | "name": "sych", 24 | "url": "https://i.ibb.co.com/3rqCPX6/fk.jpg" 25 | } 26 | ] -------------------------------------------------------------------------------- /database/totalcmd.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /database/users.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /database/©YUDA: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./settings'); 2 | const figlet = require('figlet'); 3 | const fs = require('fs'); 4 | const pino = require('pino'); 5 | const path = require('path'); 6 | const axios = require('axios'); 7 | const chalk = require('chalk'); 8 | const readline = require('readline'); 9 | const FileType = require('file-type'); 10 | const { Boom } = require('@hapi/boom'); 11 | const NodeCache = require('node-cache'); 12 | const { exec, spawn, execSync } = require('child_process'); 13 | const { parsePhoneNumber } = require('awesome-phonenumber'); 14 | const { default: WAConnection, useMultiFileAuthState, Browsers, DisconnectReason, makeInMemoryStore, makeCacheableSignalKeyStore, fetchLatestBaileysVersion, proto, getAggregateVotesInPollMessage } = require('@whiskeysockets/baileys'); 15 | 16 | const pairingCode = process.argv.includes('--qr') ? false : process.argv.includes('--pairing-code') || global.pairing_code; 17 | const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) 18 | const store = makeInMemoryStore({ logger: pino().child({ level: 'silent', stream: 'store' }) }) 19 | const question = (text) => new Promise((resolve) => rl.question(text, resolve)) 20 | 21 | global.api = (name, path = '/', query = {}, apikeyqueryname) => (name in global.APIs ? global.APIs[name] : name) + path + (query || apikeyqueryname ? '?' + decodeURIComponent(new URLSearchParams(Object.entries({ ...query, ...(apikeyqueryname ? { [apikeyqueryname]: global.APIKeys[name in global.APIs ? global.APIs[name] : name] } : {}) }))) : '') 22 | 23 | const DataBase = require('./src/database'); 24 | const database = new DataBase(global.tempatDB); 25 | const msgRetryCounterCache = new NodeCache(); 26 | 27 | (async () => { 28 | const loadData = await database.read() 29 | if (loadData && Object.keys(loadData).length === 0) { 30 | global.db = { 31 | set: {}, 32 | users: {}, 33 | game: {}, 34 | groups: {}, 35 | database: {}, 36 | ...(loadData || {}), 37 | } 38 | await database.write(global.db) 39 | } else { 40 | global.db = loadData 41 | } 42 | 43 | setInterval(async () => { 44 | if (global.db) await database.write(global.db) 45 | }, 30000) 46 | })(); 47 | 48 | const { GroupUpdate, GroupParticipantsUpdate, MessagesUpsert, Solving } = require('./src/message'); 49 | const { isUrl, generateMessageTag, getBuffer, getSizeMedia, fetchJson, sleep } = require('./lib/function'); 50 | 51 | /* 52 | * Recide By Sychyy @Naze 53 | * Follow https://github.com/nazedev 54 | * Whatsapp : https://wa.me/6287862997267 55 | */ 56 | figlet('SYCH', { font: 'Big' }, (err, data) => { 57 | if (err) { 58 | console.log('Error with figlet...'); 59 | return; 60 | } 61 | console.log(chalk.green(data)); // Display the banner in green 62 | }); 63 | async function startSychBot() { 64 | const { state, saveCreds } = await useMultiFileAuthState('nazedev'); 65 | const { version, isLatest } = await fetchLatestBaileysVersion(); 66 | const level = pino({ level: 'silent' }) 67 | 68 | const getMessage = async (key) => { 69 | if (store) { 70 | const msg = await store.loadMessage(key.remoteJid, key.id); 71 | return msg?.message || '' 72 | } 73 | return { 74 | conversation: 'Halo Saya sychy Bot' 75 | } 76 | } 77 | 78 | const sych = WAConnection({ 79 | isLatest, 80 | logger: level, 81 | getMessage, 82 | syncFullHistory: true, 83 | maxMsgRetryCount: 15, 84 | msgRetryCounterCache, 85 | retryRequestDelayMs: 10, 86 | defaultQueryTimeoutMs: 0, 87 | printQRInTerminal: !pairingCode, 88 | browser: Browsers.ubuntu('Chrome'), 89 | generateHighQualityLinkPreview: true, 90 | transactionOpts: { 91 | maxCommitRetries: 10, 92 | delayBetweenTriesMs: 10, 93 | }, 94 | appStateMacVerification: { 95 | patch: true, 96 | snapshot: true, 97 | }, 98 | auth: { 99 | creds: state.creds, 100 | keys: makeCacheableSignalKeyStore(state.keys, level), 101 | }, 102 | }) 103 | 104 | if (pairingCode && !sych.authState.creds.registered) { 105 | let phoneNumber; 106 | async function getPhoneNumber() { 107 | phoneNumber = await question('Please type your WhatsApp number : '); 108 | phoneNumber = phoneNumber.replace(/[^0-9]/g, '') 109 | 110 | if (!parsePhoneNumber(phoneNumber).valid && phoneNumber.length < 6) { 111 | console.log(chalk.bgBlack(chalk.redBright('Start with your Country WhatsApp code') + chalk.whiteBright(',') + chalk.greenBright(' Example : 62xxx'))); 112 | await getPhoneNumber() 113 | } 114 | } 115 | 116 | setTimeout(async () => { 117 | await getPhoneNumber() 118 | await exec('rm -rf ./nazedev/*') 119 | let code = await sych.requestPairingCode(phoneNumber); 120 | console.log(`Your Pairing Code : ${code}`); 121 | }, 3000) 122 | } 123 | 124 | store.bind(sych.ev) 125 | 126 | await Solving(sych, store) 127 | 128 | sych.ev.on('creds.update', saveCreds) 129 | 130 | sych.ev.on('connection.update', async (update) => { 131 | const { connection, lastDisconnect, receivedPendingNotifications } = update 132 | if (connection === 'close') { 133 | const reason = new Boom(lastDisconnect?.error)?.output.statusCode 134 | if (reason === DisconnectReason.connectionLost) { 135 | console.log('Connection to Server Lost, Attempting to Reconnect...'); 136 | startSychBot() 137 | } else if (reason === DisconnectReason.connectionClosed) { 138 | console.log('Connection closed, Attempting to Reconnect...'); 139 | startSychBot() 140 | } else if (reason === DisconnectReason.restartRequired) { 141 | console.log('Restart Required...'); 142 | startSychBot() 143 | } else if (reason === DisconnectReason.timedOut) { 144 | console.log('Connection Timed Out, Attempting to Reconnect...'); 145 | startSychBot() 146 | } else if (reason === DisconnectReason.badSession) { 147 | console.log('Delete Session and Scan again...'); 148 | startSychBot() 149 | } else if (reason === DisconnectReason.connectionReplaced) { 150 | console.log('Close current Session first...'); 151 | startSychBot() 152 | } else if (reason === DisconnectReason.loggedOut) { 153 | console.log('Scan again and Run...'); 154 | exec('rm -rf ./nazedev/*') 155 | process.exit(1) 156 | } else if (reason === DisconnectReason.Multidevicemismatch) { 157 | console.log('Scan again...'); 158 | exec('rm -rf ./nazedev/*') 159 | process.exit(0) 160 | } else { 161 | sych.end(`Unknown DisconnectReason : ${reason}|${connection}`) 162 | } 163 | } 164 | if (connection == 'open') { 165 | console.log('Connected to : ' + JSON.stringify(sych.user, null, 2)); 166 | let botNumber = await sych.decodeJid(sych.user.id); 167 | if (db.set[botNumber] && !db.set[botNumber]?.join) { 168 | if (global.my.gc.length > 0 && global.my.gc.includes('whatsapp.com')) { 169 | await sych.groupAcceptInvite(global.my.gc?.split('https://chat.whatsapp.com/')[1]).then(async grupnya => { 170 | await sych.chatModify({ archive: true }, grupnya, []) 171 | db.set[botNumber].join = true 172 | }); 173 | } 174 | } 175 | } 176 | if (receivedPendingNotifications == 'true') { 177 | console.log('Please wait About 1 Minute...') 178 | sych.ev.flush() 179 | } 180 | }); 181 | 182 | sych.ev.on('contacts.update', (update) => { 183 | for (let contact of update) { 184 | let id = sych.decodeJid(contact.id) 185 | if (store && store.contacts) store.contacts[id] = { id, name: contact.notify } 186 | } 187 | }); 188 | 189 | sych.ev.on('call', async (call) => { 190 | let botNumber = await sych.decodeJid(sych.user.id); 191 | if (db.set[botNumber].anticall) { 192 | for (let id of call) { 193 | if (id.status === 'offer') { 194 | let msg = await sych.sendMessage(id.from, { text: `Saat Ini, Kami Tidak Dapat Menerima Panggilan ${id.isVideo ? 'Video' : 'Suara'}.\nJika @${id.from.split('@')[0]} Memerlukan Bantuan, Silakan Hubungi Owner :)`, mentions: [id.from]}); 195 | await sych.sendContact(id.from, global.owner, msg); 196 | await sych.rejectCall(id.id, id.from) 197 | } 198 | } 199 | } 200 | }); 201 | 202 | sych.ev.on('groups.update', async (update) => { 203 | await GroupUpdate(sych, update, store); 204 | }); 205 | 206 | sych.ev.on('group-participants.update', async (update) => { 207 | await GroupParticipantsUpdate(sych, update, store); 208 | }); 209 | 210 | sych.ev.on('messages.upsert', async (message) => { 211 | await MessagesUpsert(sych, message, store); 212 | }); 213 | 214 | return sych 215 | } 216 | 217 | startSychBot() 218 | 219 | let file = require.resolve(__filename) 220 | fs.watchFile(file, () => { 221 | fs.unwatchFile(file) 222 | console.log(chalk.redBright(`Update ${__filename}`)) 223 | delete require.cache[file] 224 | require(file) 225 | }); -------------------------------------------------------------------------------- /lib/binary.js: -------------------------------------------------------------------------------- 1 | async function dBinary(str) { 2 | var newBin = str.split(" ") 3 | var binCode = [] 4 | for (i = 0; i < newBin.length; i++) { 5 | binCode.push(String.fromCharCode(parseInt(newBin[i], 2))) 6 | } 7 | return binCode.join("") 8 | } 9 | 10 | async function eBinary(str = ''){ 11 | let res = '' 12 | res = str.split('').map(char => { 13 | return char.charCodeAt(0).toString(2); 14 | }).join(' ') 15 | return res 16 | } 17 | 18 | module.exports = { dBinary, eBinary } -------------------------------------------------------------------------------- /lib/converter.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const { spawn } = require('child_process') 4 | 5 | function ffmpeg(buffer, args = [], ext = '', ext2 = '') { 6 | return new Promise(async (resolve, reject) => { 7 | try { 8 | let tmp = path.join(__dirname, '../database/sampah', + new Date + '.' + ext) 9 | let out = tmp + '.' + ext2 10 | await fs.promises.writeFile(tmp, buffer) 11 | spawn('ffmpeg', [ 12 | '-y', 13 | '-i', tmp, 14 | ...args, 15 | out 16 | ]) 17 | .on('error', reject) 18 | .on('close', async (code) => { 19 | try { 20 | await fs.promises.unlink(tmp) 21 | if (code !== 0) return reject(code) 22 | resolve(await fs.promises.readFile(out)) 23 | await fs.promises.unlink(out) 24 | } catch (e) { 25 | reject(e) 26 | } 27 | }) 28 | } catch (e) { 29 | reject(e) 30 | } 31 | }) 32 | } 33 | 34 | /** 35 | * Convert Audio to Playable WhatsApp Audio 36 | * @param {Buffer} buffer Audio Buffer 37 | * @param {String} ext File Extension 38 | */ 39 | function toAudio(buffer, ext) { 40 | return ffmpeg(buffer, [ 41 | '-vn', 42 | '-ac', '2', 43 | '-b:a', '128k', 44 | '-ar', '44100', 45 | '-f', 'mp3' 46 | ], ext, 'mp3') 47 | } 48 | 49 | /** 50 | * Convert Audio to Playable WhatsApp PTT 51 | * @param {Buffer} buffer Audio Buffer 52 | * @param {String} ext File Extension 53 | */ 54 | function toPTT(buffer, ext) { 55 | return ffmpeg(buffer, [ 56 | '-vn', 57 | '-c:a', 'libopus', 58 | '-b:a', '128k', 59 | '-vbr', 'on', 60 | '-compression_level', '10' 61 | ], ext, 'opus') 62 | } 63 | 64 | /** 65 | * Convert Audio to Playable WhatsApp Video 66 | * @param {Buffer} buffer Video Buffer 67 | * @param {String} ext File Extension 68 | */ 69 | function toVideo(buffer, ext) { 70 | return ffmpeg(buffer, [ 71 | '-c:v', 'libx264', 72 | '-c:a', 'aac', 73 | '-ab', '128k', 74 | '-ar', '44100', 75 | '-crf', '32', 76 | '-preset', 'slow' 77 | ], ext, 'mp4') 78 | } 79 | 80 | module.exports = { 81 | toAudio, 82 | toPTT, 83 | toVideo, 84 | ffmpeg, 85 | } 86 | -------------------------------------------------------------------------------- /lib/exif.js: -------------------------------------------------------------------------------- 1 | require('../settings'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const { tmpdir } = require('os'); 5 | const Crypto = require('crypto'); 6 | const ff = require('fluent-ffmpeg'); 7 | const FileType = require('file-type'); 8 | const webp = require('node-webpmux'); 9 | 10 | async function imageToWebp(media) { 11 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 12 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.jpg`) 13 | fs.writeFileSync(tmpFileIn, media) 14 | await new Promise((resolve, reject) => { 15 | ff(tmpFileIn) 16 | .on("error", reject) 17 | .on("end", () => resolve(true)) 18 | .addOutputOptions([ 19 | "-vcodec", 20 | "libwebp", 21 | "-vf", 22 | "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15, pad=320:320:-1:-1:color=white@0.0, split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse" 23 | ]) 24 | .toFormat("webp") 25 | .save(tmpFileOut) 26 | }) 27 | 28 | const buff = fs.readFileSync(tmpFileOut) 29 | fs.unlinkSync(tmpFileOut) 30 | fs.unlinkSync(tmpFileIn) 31 | return buff 32 | } 33 | 34 | async function videoToWebp(media) { 35 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 36 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.mp4`) 37 | fs.writeFileSync(tmpFileIn, media) 38 | await new Promise((resolve, reject) => { 39 | ff(tmpFileIn) 40 | .on("error", reject) 41 | .on("end", () => resolve(true)) 42 | .addOutputOptions([ 43 | "-vcodec", 44 | "libwebp", 45 | "-vf", 46 | "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15, pad=320:320:-1:-1:color=white@0.0, split [a][b]; [a] palettegen=reserve_transparent=on:transparency_color=ffffff [p]; [b][p] paletteuse", 47 | "-loop", 48 | "0", 49 | "-ss", 50 | "00:00:00", 51 | "-t", 52 | "00:00:05", 53 | "-preset", 54 | "default", 55 | "-an", 56 | "-vsync", 57 | "0" 58 | ]) 59 | .toFormat("webp") 60 | .save(tmpFileOut) 61 | }) 62 | 63 | const buff = fs.readFileSync(tmpFileOut) 64 | fs.unlinkSync(tmpFileOut) 65 | fs.unlinkSync(tmpFileIn) 66 | return buff 67 | } 68 | 69 | async function writeExif(media, data) { 70 | const anu = await FileType.fromBuffer(media) 71 | const wMedia = /webp/.test(anu.mime) ? media : /jpeg|jpg|png/.test(anu.mime) ? await imageToWebp(media) : /video/.test(anu.mime) ? await videoToWebp(media) : "" 72 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 73 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 74 | fs.writeFileSync(tmpFileIn, wMedia) 75 | if (data) { 76 | const img = new webp.Image() 77 | const wr = { a: global.author ? global.author : 'naze-dev', b: data.packname ? data.packname : global.packname ? global.packname : 'Bot WhatsApp', c: data.author ? data.author : global.author ? global.author : 'Nazedev', d: data.categories ? data.categories : [""], e: data.isAvatar ? data.isAvatar : 0 } 78 | const json = { 'sticker-pack-id': wr.a, 'sticker-pack-name': wr.b, 'sticker-pack-publisher': wr.c, 'emojis': wr.d, 'is-avatar-sticker': wr.e }; 79 | const exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]) 80 | const jsonBuff = Buffer.from(JSON.stringify(json), 'utf-8') 81 | const exif = Buffer.concat([exifAttr, jsonBuff]) 82 | exif.writeUIntLE(jsonBuff.length, 14, 4) 83 | await img.load(tmpFileIn) 84 | fs.unlinkSync(tmpFileIn) 85 | img.exif = exif 86 | await img.save(tmpFileOut) 87 | return tmpFileOut 88 | } 89 | } 90 | 91 | module.exports = { imageToWebp, videoToWebp, writeExif } 92 | -------------------------------------------------------------------------------- /lib/function.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const util = require('util'); 3 | const Jimp = require('jimp'); 4 | const axios = require('axios'); 5 | const chalk = require('chalk'); 6 | const crypto = require('crypto'); 7 | const FileType = require('file-type'); 8 | const moment = require('moment-timezone'); 9 | const { defaultMaxListeners } = require('stream'); 10 | const { sizeFormatter } = require('human-readable'); 11 | const { exec, spawn, execSync } = require('child_process'); 12 | const { proto, areJidsSameUser, extractMessageContent, downloadContentFromMessage, getContentType, getDevice } = require('@whiskeysockets/baileys'); 13 | const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'.split(''); 14 | 15 | const unixTimestampSeconds = (date = new Date()) => Math.floor(date.getTime() / 1000) 16 | 17 | const generateMessageTag = (epoch) => { 18 | let tag = (0, unixTimestampSeconds)().toString(); 19 | if (epoch) 20 | tag += '.--' + epoch; 21 | return tag; 22 | } 23 | 24 | const processTime = (timestamp, now) => { 25 | return moment.duration(now - moment(timestamp * 1000)).asSeconds() 26 | } 27 | 28 | const webApi = (a, b, c, d, e, f) => { 29 | const hasil = a + b + c + d + e + f; 30 | return hasil; 31 | } 32 | 33 | const getRandom = (ext) => { 34 | return `${Math.floor(Math.random() * 10000)}${ext}` 35 | } 36 | 37 | const getBuffer = async (url, options) => { 38 | try { 39 | options ? options : {} 40 | const res = await axios({ 41 | method: "get", 42 | url, 43 | headers: { 44 | 'DNT': 1, 45 | 'Upgrade-Insecure-Request': 1 46 | }, 47 | ...options, 48 | responseType: 'arraybuffer' 49 | }) 50 | return res.data 51 | } catch (err) { 52 | return err 53 | } 54 | } 55 | 56 | const fetchJson = async (url, options) => { 57 | try { 58 | options ? options : {} 59 | const res = await axios({ 60 | method: 'GET', 61 | url: url, 62 | headers: { 63 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36' 64 | }, 65 | ...options 66 | }) 67 | return res.data 68 | } catch (err) { 69 | return err 70 | } 71 | } 72 | 73 | const runtime = function(seconds) { 74 | seconds = Number(seconds); 75 | var d = Math.floor(seconds / (3600 * 24)); 76 | var h = Math.floor(seconds % (3600 * 24) / 3600); 77 | var m = Math.floor(seconds % 3600 / 60); 78 | var s = Math.floor(seconds % 60); 79 | var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : ""; 80 | var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : ""; 81 | var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : ""; 82 | var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : ""; 83 | return dDisplay + hDisplay + mDisplay + sDisplay; 84 | } 85 | 86 | const clockString = (ms) => { 87 | let h = isNaN(ms) ? '--' : Math.floor(ms / 3600000) 88 | let m = isNaN(ms) ? '--' : Math.floor(ms / 60000) % 60 89 | let s = isNaN(ms) ? '--' : Math.floor(ms / 1000) % 60 90 | return [h, m, s].map(v => v.toString().padStart(2, 0)).join(':') 91 | } 92 | 93 | const sleep = async (ms) => { 94 | return new Promise(resolve => setTimeout(resolve, ms)); 95 | } 96 | 97 | const isUrl = (url) => { 98 | 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')) 99 | } 100 | 101 | const getTime = (format, date) => { 102 | if (date) { 103 | return moment(date).locale('id').format(format) 104 | } else { 105 | return moment.tz('Asia/Jakarta').locale('id').format(format) 106 | } 107 | } 108 | 109 | const formatDate = (n, locale = 'id') => { 110 | let d = new Date(n) 111 | return d.toLocaleDateString(locale, { 112 | weekday: 'long', 113 | day: 'numeric', 114 | month: 'long', 115 | year: 'numeric', 116 | hour: 'numeric', 117 | minute: 'numeric', 118 | second: 'numeric' 119 | }) 120 | } 121 | 122 | const tanggal = (numer) => { 123 | myMonths = ["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","November","Desember"]; 124 | myDays = ['Minggu','Senin','Selasa','Rabu','Kamis','Jum’at','Sabtu']; 125 | var tgl = new Date(numer); 126 | var day = tgl.getDate() 127 | bulan = tgl.getMonth() 128 | var thisDay = tgl.getDay(), 129 | thisDay = myDays[thisDay]; 130 | var yy = tgl.getYear() 131 | var year = (yy < 1000) ? yy + 1900 : yy; 132 | const time = moment.tz('Asia/Jakarta').format('DD/MM HH:mm:ss') 133 | let d = new Date 134 | let locale = 'id' 135 | let gmt = new Date(0).getTime() - new Date('1 January 1970').getTime() 136 | let weton = ['Pahing', 'Pon','Wage','Kliwon','Legi'][Math.floor(((d * 1) + gmt) / 84600000) % 5] 137 | return`${thisDay}, ${day} - ${myMonths[bulan]} - ${year}` 138 | } 139 | 140 | const formatp = sizeFormatter({ 141 | std: 'JEDEC', //'SI' = default | 'IEC' | 'JEDEC' 142 | decimalPlaces: 2, 143 | keepTrailingZeroes: false, 144 | render: (literal, symbol) => `${literal} ${symbol}B`, 145 | }) 146 | 147 | const jsonformat = (string) => { 148 | return JSON.stringify(string, null, 2) 149 | } 150 | 151 | const reSize = async (image, ukur1 = 100, ukur2 = 100) => { 152 | return new Promise(async(resolve, reject) => { 153 | try { 154 | const read = await Jimp.read(image); 155 | const result = await read.resize(ukur1, ukur2).getBufferAsync(Jimp.MIME_JPEG) 156 | resolve(result) 157 | } catch (e) { 158 | reject(e) 159 | } 160 | }) 161 | } 162 | 163 | const toHD = async (image) => { 164 | return new Promise(async(resolve, reject) => { 165 | try { 166 | const read = await Jimp.read(image); 167 | const newWidth = read.bitmap.width * 4; 168 | const newHeight = read.bitmap.height * 4; 169 | const result = await read.resize(newWidth, newHeight).getBufferAsync(Jimp.MIME_JPEG) 170 | resolve(result) 171 | } catch (e) { 172 | reject(e) 173 | } 174 | }) 175 | } 176 | 177 | const logic = (check, inp, out) => { 178 | if (inp.length !== out.length) throw new Error('Input and Output must have same length') 179 | for (let i in inp) 180 | if (util.isDeepStrictEqual(check, inp[i])) return out[i] 181 | return null 182 | } 183 | 184 | const generateProfilePicture = async (buffer) => { 185 | const jimp = await Jimp.read(buffer) 186 | const min = jimp.getWidth() 187 | const max = jimp.getHeight() 188 | const cropped = jimp.crop(0, 0, min, max) 189 | return { 190 | img: await cropped.scaleToFit(720, 720).getBufferAsync(Jimp.MIME_JPEG), 191 | preview: await cropped.scaleToFit(720, 720).getBufferAsync(Jimp.MIME_JPEG) 192 | } 193 | } 194 | 195 | const bytesToSize = (bytes, decimals = 2) => { 196 | if (bytes === 0) return '0 Bytes'; 197 | const k = 1024; 198 | const dm = decimals < 0 ? 0 : decimals; 199 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; 200 | const i = Math.floor(Math.log(bytes) / Math.log(k)); 201 | return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; 202 | } 203 | 204 | const checkBandwidth = async () => { 205 | let ind = 0; 206 | let out = 0; 207 | for (let i of await require('node-os-utils').netstat.stats()) { 208 | ind += parseInt(i.inputBytes); 209 | out += parseInt(i.outputBytes); 210 | } 211 | return { 212 | download: bytesToSize(ind), 213 | upload: bytesToSize(out), 214 | } 215 | } 216 | 217 | const getSizeMedia = async (path) => { 218 | return new Promise((resolve, reject) => { 219 | if (typeof path === 'string' && /http/.test(path)) { 220 | axios.get(path).then((res) => { 221 | let length = parseInt(res.headers['content-length']) 222 | if(!isNaN(length)) resolve(bytesToSize(length, 3)) 223 | }) 224 | } else if (Buffer.isBuffer(path)) { 225 | let length = Buffer.byteLength(path) 226 | if(!isNaN(length)) resolve(bytesToSize(length, 3)) 227 | } else { 228 | reject(0) 229 | } 230 | }) 231 | } 232 | 233 | const parseMention = (text = '') => { 234 | return [...text.matchAll(/@([0-9]{5,16}|0)/g)].map(v => v[1] + '@s.whatsapp.net') 235 | } 236 | 237 | const getGroupAdmins = (participants) => { 238 | let admins = [] 239 | for (let i of participants) { 240 | i.admin === "superadmin" ? admins.push(i.id) : i.admin === "admin" ? admins.push(i.id) : '' 241 | } 242 | return admins || [] 243 | } 244 | 245 | const getHashedPassword = (password) => { 246 | const sha256 = crypto.createHash('sha256'); 247 | const hash = sha256.update(password).digest('base64'); 248 | return hash; 249 | } 250 | 251 | const generateAuthToken = (size) => { 252 | return crypto.randomBytes(size).toString('hex').slice(0, size); 253 | } 254 | 255 | const cekMenfes = (tag, nomer, db_menfes) => { 256 | let x1 = false 257 | Object.keys(db_menfes).forEach((i) => { 258 | if (db_menfes[i].id == nomer){ 259 | x1 = i 260 | } 261 | }) 262 | if (x1 !== false) { 263 | if (tag == 'id'){ 264 | return db_menfes[x1].id 265 | } 266 | if (tag == 'teman'){ 267 | return db_menfes[x1].teman 268 | } 269 | } 270 | if (x1 == false) { 271 | return null 272 | } 273 | } 274 | 275 | function format(...args) { 276 | return util.format(...args) 277 | } 278 | 279 | function generateToken() { 280 | let characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*'; 281 | let token = ''; 282 | for (let i = 0; i < 8; i++) { 283 | let randomIndex = Math.floor(Math.random() * characters.length); 284 | token += characters.charAt(randomIndex); 285 | } 286 | return token; 287 | } 288 | 289 | function batasiTeks(teks, batas) { 290 | if (teks.length <= batas) { 291 | return teks; 292 | } else { 293 | return teks.substring(0, batas) + '...'; 294 | } 295 | } 296 | 297 | function randomText(len) { 298 | const result = []; 299 | for (let i = 0; i < len; i++) result.push(pool[Math.floor(Math.random() * pool.length)]); 300 | return result.join(''); 301 | } 302 | 303 | function isEmoji(str) { 304 | const emojiRegex = /[\u{1F000}-\u{1F6FF}\u{1F900}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F100}-\u{1F1FF}]/u; 305 | return emojiRegex.test(str); 306 | } 307 | 308 | function readFileTxt(file) { 309 | return new Promise((resolve, reject) => { 310 | const data = fs.readFileSync(file, 'utf8'); 311 | const array = data.toString().split('\n') ; 312 | const random = array[Math.floor(Math.random() * array.length)]; 313 | resolve(random.replace('\r', '')); 314 | }) 315 | } 316 | 317 | function readFileJson(file) { 318 | return new Promise((resolve, reject) => { 319 | const jsonData = JSON.parse(fs.readFileSync(file)); 320 | const index = Math.floor(Math.random() * jsonData.length); 321 | const random = jsonData[index]; 322 | resolve(random); 323 | }) 324 | } 325 | 326 | async function getTypeUrlMedia(url) { 327 | return new Promise(async (resolve, reject) => { 328 | try { 329 | const buffer = await axios.get(url, { responseType: 'arraybuffer' }); 330 | const type = buffer.headers['content-type'] || (await FileType.fromBuffer(buffer.data)).mime 331 | resolve({ type, url }) 332 | } catch (e) { 333 | reject(e) 334 | } 335 | }) 336 | } 337 | 338 | function pickRandom(list) { 339 | return list[Math.floor(list.length * Math.random())] 340 | } 341 | 342 | function isCommandAvailable(command) { 343 | try { 344 | execSync(`command -v ${command}`); 345 | return true; 346 | } catch (error) { 347 | return false; 348 | } 349 | } 350 | 351 | async function getAllHTML(urls) { 352 | try { 353 | const htmlArr = []; 354 | for (const url of urls) { 355 | const response = await axios.get(url); 356 | htmlArr.push(response.data); 357 | } 358 | return htmlArr; 359 | } catch (error) { 360 | console.error(error); 361 | } 362 | } 363 | 364 | module.exports = { unixTimestampSeconds, generateMessageTag, processTime, webApi, getRandom, getBuffer, fetchJson, runtime, clockString, sleep, isUrl, getTime, formatDate, tanggal, formatp, jsonformat, reSize, toHD, logic, generateProfilePicture, bytesToSize, checkBandwidth, getSizeMedia, parseMention, getGroupAdmins, readFileTxt, readFileJson, isCommandAvailable, getHashedPassword, generateAuthToken, cekMenfes, generateToken, batasiTeks, randomText, isEmoji, getTypeUrlMedia, pickRandom, getAllHTML }; 365 | 366 | let file = require.resolve(__filename) 367 | fs.watchFile(file, () => { 368 | fs.unwatchFile(file) 369 | console.log(chalk.redBright(`Update ${__filename}`)) 370 | delete require.cache[file] 371 | require(file) 372 | }) -------------------------------------------------------------------------------- /lib/game.js: -------------------------------------------------------------------------------- 1 | require('../settings'); 2 | const { sleep, clockString } = require('./function') 3 | 4 | function pickRandom(list) { 5 | return list[Math.floor(list.length * Math.random())] 6 | } 7 | 8 | const rdGame = (bd, id, tm) => Object.keys(bd).find(a => a.startsWith(id) && a.endsWith(tm)); 9 | const iGame = (bd, id) => (a => a && bd[a].id)(Object.keys(bd).find(a => a.startsWith(id))); 10 | const tGame = (bd, id) => (a => a && bd[a].time)(Object.keys(bd).find(a => a.startsWith(id))); 11 | 12 | const gameSlot = async (conn, m, db) => { 13 | if (db.users[m.sender].limit < 1) return m.reply(global.mess.limit) 14 | const sotoy = ['🍇','🍉','🍋','🍌','🍎','🍑','🍒','🫐','🥥','🥑'] 15 | const slot1 = pickRandom(sotoy) 16 | const slot2 = pickRandom(sotoy) 17 | const slot3 = pickRandom(sotoy) 18 | const listSlot1 = `${pickRandom(sotoy)} : ${pickRandom(sotoy)} : ${pickRandom(sotoy)}` 19 | const listSlot2 = `${slot1} : ${slot2} : ${slot3}` 20 | const listSlot3 = `${pickRandom(sotoy)} : ${pickRandom(sotoy)} : ${pickRandom(sotoy)}` 21 | const randomLimit = Math.floor(Math.random() * 10) 22 | const botNumber = await conn.decodeJid(conn.user.id) 23 | try { 24 | if (slot1 === slot2 && slot2 === slot3) { 25 | db.users[m.sender].limit -= 1 26 | db.set[botNumber].limit += 1 27 | let sloth =`[ 🎰VIRTUAL SLOT 🎰 ]\n------------------------\n\n${listSlot1}\n${listSlot2} <=====\n${listSlot3}\n\n------------------------\n[ 🎰 VIRTUAL SLOT 🎰 ]\n\n*Keterangan* :\n_You Win🎉_ <=====Limit + ${randomLimit}, Uang + ${randomLimit * 500}` 28 | conn.sendMessage(m.chat, { text: sloth }, { quoted: m }) 29 | db.users[m.sender].limit += randomLimit 30 | db.users[m.sender].uang += randomLimit * 500 31 | } else { 32 | db.users[m.sender].limit -= 1 33 | db.set[botNumber].limit += 1 34 | let sloth =`[ 🎰VIRTUAL SLOT 🎰 ]\n------------------------\n\n${listSlot1}\n${listSlot2} <=====\n${listSlot3}\n\n------------------------\n[ 🎰 VIRTUAL SLOT 🎰 ]\n\n*Keterangan* :\n_You Lose_ <=====\nLimit - 1` 35 | conn.sendMessage(m.chat, { text: sloth }, { quoted: m }) 36 | } 37 | } catch (e) { 38 | console.log(e) 39 | m.reply('Error!') 40 | } 41 | } 42 | 43 | const gameCasinoSolo = async (conn, m, prefix, db) => { 44 | try { 45 | let buatall = 1 46 | const botNumber = await conn.decodeJid(conn.user.id) 47 | let randomaku = `${Math.floor(Math.random() * 101)}`.trim() 48 | let randomkamu = `${Math.floor(Math.random() * 81)}`.trim() //hehe Biar Susah Menang :v 49 | let Aku = (randomaku * 1) 50 | let Kamu = (randomkamu * 1) 51 | let count = m.args[0] 52 | count = count ? 'all' === count ? Math.floor(db.users[m.sender].uang / buatall) : parseInt(count) : m.args[0] ? parseInt(m.args[0]) : 1 53 | count = Math.max(1, count) 54 | if (m.args.length < 1) return m.reply(prefix + 'casino \n' + prefix + 'casino 1000') 55 | if (isNaN(m.args[0])) return m.reply(`Masukkan jumlahnya!\nContoh : ${prefix + m.command} 1000`) 56 | if (db.users[m.sender].uang >= count * 1) { 57 | db.users[m.sender].uang -= count * 1 58 | db.set[botNumber].uang += count * 1 59 | if (Aku > Kamu) { 60 | m.reply(`💰 Casino 💰\n*Kamu:* ${Kamu} Point\n*Computer:* ${Aku} Point\n\n*You LOSE*\nKamu kehilangan ${count} Uang`.trim()) 61 | } else if (Aku < Kamu) { 62 | db.users[m.sender].uang += count * 2 63 | m.reply(`💰 Casino 💰\n*Kamu:* ${Kamu} Point\n*Computer:* ${Aku} Point\n\n*You Win*\nKamu mendapatkan ${count * 2} Uang`.trim()) 64 | } else { 65 | db.users[m.sender].uang += count * 1 66 | m.reply(`💰 Casino 💰\n*Kamu:* ${Kamu} Point\n*Computer:* ${Aku} Point\n\n*SERI*\nKamu mendapatkan ${count * 1} Uang`.trim()) 67 | } 68 | } else { 69 | m.reply(`Uang kamu tidak mencukupi untuk Casino silahkan *kumpulkan* terlebih dahulu!`) 70 | } 71 | } catch (e) { 72 | console.log(e) 73 | m.reply('Error!!') 74 | } 75 | } 76 | 77 | const gameMerampok = async (m, db) => { 78 | let __timers = (new Date - db.users[m.sender].lastrampok) 79 | let _timers = (3600000 - __timers) 80 | let timers = clockString(_timers) 81 | if (new Date - db.users[m.sender].lastrampok > 3600000) { 82 | let dapat = (Math.floor(Math.random() * 10000)) 83 | let who 84 | if (m.isGroup) who = m.mentionedJid ? m.mentionedJid[0] : m.quoted ? m.quoted.sender : m.mentionedJid[0] 85 | else who = m.chat 86 | if (!who) return m.reply('Tag salah satu') 87 | if (!db.users[who]) return m.reply('Target tidak terdaftar di database!') 88 | if (10000 > db.users[who].uang) return m.reply('Targetnya Kismin ngab🗿') 89 | db.users[who].uang -= dapat 90 | db.users[m.sender].uang += dapat 91 | db.users[m.sender].lastrampok = new Date * 1 92 | m.reply(`Berhasil Merampok Money Target Sebesar ${dapat}`) 93 | } else { 94 | m.reply(`Anda Sudah merampok dan berhasil sembunyi, tunggu ${timers} untuk merampok lagi`) 95 | } 96 | } 97 | 98 | const gameBegal = async (conn, m, db) => { 99 | let user = db.users[m.sender] 100 | let __timers = (new Date - user.lastbegal) 101 | let _timers = (3600000 - __timers) 102 | let timers = clockString(_timers) 103 | const randomUang = Math.floor(Math.random() * 10001) 104 | let random = [{teks: 'Pemain Berhasil Kabur!', no: 0},{teks: 'Pemain Melarikan Diri!', no: 0},{teks: 'Pemain Bersembunyi', no: 0},{teks: 'Pemain Bunuh Diri', no: 2},{teks: 'Pemain Berhasil Tertangkap', no: 2},{teks: 'Pemain Tidak Di Temukan!', no: 0},{teks: 'Pemain Lebih Kuat Dari Kamu!', no: 1},{teks: 'Pemain Menggunakan Cheat', no: 1},{teks: 'Pemain Lapor Polisi', no: 0},{teks: 'Pemain Tertangkap!', no: 2},{teks: 'Pemain Menyerahkan Diri', no: 2}] 105 | let teksnya = await pickRandom(random); 106 | if (new Date - user.lastbegal > 3600000) { 107 | let { key } = await conn.sendMessage(m.chat, { text: 'Sedang Mencari Pemain...' }) 108 | await sleep(2000) 109 | if (teksnya.no === 0) { 110 | await conn.sendMessage(m.chat, { text: teksnya.teks, edit: key }) 111 | await conn.sendMessage(m.chat, { text: 'Gagal Mencari Pemain, Silahkan Coba lagi' }, { quoted: m }) 112 | } else if (teksnya.no === 1) { 113 | await conn.sendMessage(m.chat, { text: teksnya.teks, edit: key }) 114 | await conn.sendMessage(m.chat, { text: `Kamu Di Bunuh Oleh Pemain\nUang Kamu Di Rampas Sebesar *${randomUang}*` }, { quoted: m }) 115 | db.users[m.sender].uang -= randomUang 116 | } else { 117 | await conn.sendMessage(m.chat, { text: teksnya.teks, edit: key }) 118 | await conn.sendMessage(m.chat, { text: `Berhasil Mendapatkan Uang Sebesar : *${randomUang}*` }, { quoted: m }) 119 | db.users[m.sender].uang += randomUang 120 | db.users[m.sender].lastbegal = new Date * 1 121 | } 122 | } else { 123 | conn.sendMessage(m.chat, { text: `Silahkan tunggu *⏱️${timers}* lagi untuk bisa bermain lagi` }, { quoted: m }) 124 | } 125 | } 126 | 127 | const daily = async (m, db) => { 128 | let user = db.users[m.sender] 129 | let __timers = (new Date - user.lastclaim) 130 | let _timers = (86400000 - __timers) 131 | let timers = clockString(_timers) 132 | if (new Date - user.lastclaim > 86400000) { 133 | m.reply(`*Daily Claim*\n_Berhasil Claim_\n- limit : 10\n- uang : 10000\n\n_Claim Di Reset_`) 134 | db.users[m.sender].limit += 10 135 | db.users[m.sender].uang += 10000 136 | db.users[m.sender].lastclaim = new Date * 1 137 | } else { 138 | m.reply(`Silahkan tunggu *⏱️${timers}* lagi untuk bisa mengclaim lagi`) 139 | } 140 | } 141 | 142 | const buy = async (m, args, db) => { 143 | if (args[0] === 'limit') { 144 | if (!args[1]) return m.reply(`Masukkan Nominalnya!\nExample : ${m.prefix + m.command} limit 10`); 145 | let count = parseInt(args[1]) 146 | if (db.users[m.sender].uang >= count * 1) { 147 | db.users[m.sender].limit += count * 1 148 | db.users[m.sender].uang -= count * 500 149 | m.reply(`Berhasil Membeli Limit Sebanyak ${args[1] * 1} dengan harga ${args[1] * 500}`); 150 | } else { 151 | m.reply(`Uang Kamu Tidak Cukup Untuk Membeli limit!\nUangmu Tersisa : ${db.users[m.sender].uang}\nHarga ${args[1]} Limit : ${args[1] * 500}`); 152 | } 153 | } else { 154 | m.reply(`Harga Limit : Jumlah x 500\n• 1 limit = 500\n• 2 limit = 1000\n\nExample : .buy limit 3`); 155 | } 156 | } 157 | 158 | const setLimit = (m, db) => db.users[m.sender].limit -= 1 159 | 160 | const addLimit = (jumlah, no, db) => db.users[no].limit += parseInt(jumlah) 161 | 162 | const setUang = (m, db) => db.users[m.sender].uang -= 1000 163 | 164 | const addUang = (jumlah, no, db) => db.users[no].uang += parseInt(jumlah) 165 | 166 | const transfer = async (m, args, db) => { 167 | if (args[0] == 'limit') { 168 | if (!args[1].length > 7) return m.reply(`Transfer Menu :\nExample : ${m.prefix + m.command} limit @tag 11\n• ${m.prefix + m.command} limit @tag jumlah\n• ${m.prefix + m.command} uang @tag jumlah`); 169 | let count = parseInt(args[2] && args[2].length > 0 ? Math.min(9999999, Math.max(parseInt(args[2]), 1)) : Math.min(1)) 170 | let who = m.mentionedJid[0] ? m.mentionedJid[0] : m.quoted ? m.quoted.sender : args[1] ? (args[1].replace(/[^0-9]/g, '') + '@s.whatsapp.net') : false 171 | if (!who) return m.reply('Siapa yg mau di transfer?') 172 | if (db.users[who]) { 173 | if (db.users[m.sender].limit >= count * 1) { 174 | try { 175 | db.users[m.sender].limit -= count * 1 176 | db.users[who].limit += count * 1 177 | m.reply(`Berhasil mentransfer limit sebesar ${count}, kepada @${who.split('@')[0]}`) 178 | } catch (e) { 179 | db.users[m.sender].limit += count * 1 180 | m.reply('Gagal Transfer') 181 | } 182 | } else { 183 | m.reply(`Limit tidak mencukupi!!\nLimit mu tersisa : *${db.users[m.sender].limit}*`) 184 | } 185 | } else m.reply(`Nomer ${who.split('@')[0]} Bukan User bot!`) 186 | } else if (args[0] == 'uang') { 187 | if (!args[1].length > 7) return m.reply(`Transfer Menu :\nExample : ${m.prefix + m.command} limit @tag 11\n• ${m.prefix + m.command} limit @tag jumlah\n• ${m.prefix + m.command} uang @tag jumlah`); 188 | let count = parseInt(args[2] && args[2].length > 0 ? Math.min(9999999, Math.max(parseInt(args[2]), 1)) : Math.min(1)) 189 | let who = m.mentionedJid[0] ? m.mentionedJid[0] : m.quoted ? m.quoted.sender : args[1] ? (args[1].replace(/[^0-9]/g, '') + '@s.whatsapp.net') : false 190 | if (!who) return m.reply('Siapa yg mau di transfer?') 191 | if (db.users[who]) { 192 | if (db.users[m.sender].uang >= count * 1) { 193 | try { 194 | db.users[m.sender].uang -= count * 1 195 | db.users[who].uang += count * 1 196 | m.reply(`Berhasil mentransfer uang sebesar ${count}, kepada @${who.split('@')[0]}`) 197 | } catch (e) { 198 | db.users[m.sender].uang += count * 1 199 | m.reply('Gagal Transfer') 200 | } 201 | } else { 202 | m.reply(`Uang tidak mencukupi!!\Uang mu tersisa : *${db.users[m.sender].uang}*`) 203 | } 204 | } else m.reply(`Nomer ${who.split('@')[0]} Bukan User bot!`) 205 | } else { 206 | m.reply(`Transfer Menu :\nExample : ${m.prefix + m.command} limit @tag 11\n• ${m.prefix + m.command} limit @tag jumlah\n• ${m.prefix + m.command} uang @tag jumlah`); 207 | } 208 | } 209 | 210 | module.exports = { rdGame, iGame, tGame, gameSlot, gameCasinoSolo, gameMerampok, gameBegal, daily, buy, setLimit, addLimit, addUang, setUang, transfer } -------------------------------------------------------------------------------- /lib/math.js: -------------------------------------------------------------------------------- 1 | let modes = { 2 | noob: [-3, 3,-3, 3, '+-', 15000, 10], 3 | easy: [-10, 10, -10, 10, '*/+-', 20000, 40], 4 | medium: [-40, 40, -20, 20, '*/+-', 40000, 150], 5 | hard: [-100, 100, -70, 70, '*/+-', 60000, 350], 6 | extreme: [-999999, 999999, -999999, 999999, '*/', 99999, 9999], 7 | impossible: [-99999999999, 99999999999, -99999999999, 999999999999, '*/', 30000, 35000], 8 | impossible2: [-999999999999999, 999999999999999, -999, 999, '/', 30000, 50000] 9 | } 10 | 11 | let operators = { 12 | '+': '+', 13 | '-': '-', 14 | '*': '×', 15 | '/': '÷' 16 | } 17 | 18 | function randomInt(from, to) { 19 | if (from > to) [from, to] = [to, from] 20 | from = Math.floor(from) 21 | to = Math.floor(to) 22 | return Math.floor((to - from) * Math.random() + from) 23 | } 24 | 25 | function pickRandom(list) { 26 | return list[Math.floor(Math.random() * list.length)] 27 | } 28 | 29 | function genMath(mode) { 30 | return new Promise((resolve, reject) => { 31 | let [a1, a2, b1, b2, ops, time, bonus] = modes[mode] 32 | let a = randomInt(a1, a2) 33 | let b = randomInt(b1, b2) 34 | let op = pickRandom([...ops]) 35 | let result = (new Function(`return ${a} ${op.replace('/', '*')} ${b < 0 ? `(${b})` : b}`))() 36 | if (op == '/') [a, result] = [result, a] 37 | hasil = { 38 | soal: `${a} ${operators[op]} ${b}`, 39 | mode: mode, 40 | waktu: time, 41 | hadiah: bonus, 42 | jawaban: result 43 | } 44 | resolve(hasil) 45 | }) 46 | } 47 | 48 | module.exports = { modes, operators, randomInt, pickRandom, genMath } 49 | -------------------------------------------------------------------------------- /lib/pixiv.js: -------------------------------------------------------------------------------- 1 | const { URL_REGEX } = require('@whiskeysockets/baileys') 2 | const { Pixiv } = require ( '@ibaraki-douji/pixivts') 3 | const pixiv = new Pixiv() 4 | 5 | 6 | async function pixivdl(query) { 7 | if (query.match(URL_REGEX)) { 8 | if (!/https:\/\/www.pixiv.net\/en\/artworks\/[0-9]+/i.test(query)) throw 'Invalid Pixiv Url' 9 | query = query.replace(/\D/g, '') 10 | let res = await pixiv.getIllustByID(query).catch(() => null) 11 | if (!res) throw `ID "${query}" not found :/` 12 | let media = [] 13 | for (let x = 0; x < res.urls.length; x++) media.push(await pixiv.download(new URL(res.urls[x].original))) 14 | return { 15 | artist: res.user.name, caption: res.title, tags: res.tags.tags.map(v => v.tag), media 16 | } 17 | } else { 18 | let res = await pixiv.getIllustsByTag(query) 19 | if (!res.length) throw `Tag's "${query}" not found :/` 20 | res = res[~~(Math.random() * res.length)].id 21 | res = await pixiv.getIllustByID(res) 22 | let media = [] 23 | for (let x = 0; x < res.urls.length; x++) media.push(await pixiv.download(new URL(res.urls[x].original))) 24 | return { 25 | artist: res.user.name, caption: res.title, tags: res.tags.tags.map(v => v.tag), media 26 | } 27 | } 28 | } 29 | 30 | module.exports = { pixivdl } -------------------------------------------------------------------------------- /lib/screaper.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const https = require('https'); 4 | const axios = require('axios'); 5 | const yts = require('yt-search'); 6 | const ytdl = require('ytdl-core'); 7 | const cheerio = require('cheerio'); 8 | const fetch = require('node-fetch'); 9 | const FormData = require('form-data'); 10 | const { exec, spawn, execSync } = require('child_process'); 11 | 12 | async function bytesToSize(bytes) { 13 | const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; 14 | if (bytes === 0) return "n/a"; 15 | const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10); 16 | if (i === 0) resolve(`${bytes} ${sizes[i]}`); 17 | return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`; 18 | } 19 | 20 | const axioss = axios.create({ 21 | httpsAgent: new https.Agent({ rejectUnauthorized: false }), 22 | }); 23 | 24 | async function mediafireDl(url) { 25 | return new Promise(async (resolve, reject) => { 26 | try { 27 | const res = await axioss.get(url, { 28 | headers: { 29 | 'User-Agent': 'Mozilla/5.0 (Windows; Windows NT 6.0; WOW64; en-US) Gecko/20130401 Firefox/51.2' 30 | } 31 | }); 32 | const $ = cheerio.load(res.data); 33 | const link = $('a#downloadButton').attr('href'); 34 | const size = $('a#downloadButton').text().replace('Download', '').replace('(', '').replace(')', '').trim(); 35 | const upload_date = $('.dl-info .details li').last().find('span').text().trim(); 36 | const name = link.split('/')[5]; 37 | const type = name.split('.')[1] || ''; 38 | resolve({ name, type, upload_date, size, link }) 39 | } catch (e) { 40 | reject(e) 41 | } 42 | }) 43 | } 44 | 45 | async function pinterest(query) { 46 | return new Promise(async(resolve,reject) => { 47 | axios.get('https://id.pinterest.com/search/pins/?autologin=true&q=' + query, { 48 | headers: { 49 | 'cookie': '_auth=1; _b=\"AVna7S1p7l1C5I9u0+nR3YzijpvXOPc6d09SyCzO+DcwpersQH36SmGiYfymBKhZcGg=\"; _pinterest_sess=TWc9PSZHamJOZ0JobUFiSEpSN3Z4a2NsMk9wZ3gxL1NSc2k2NkFLaUw5bVY5cXR5alZHR0gxY2h2MVZDZlNQalNpUUJFRVR5L3NlYy9JZkthekp3bHo5bXFuaFZzVHJFMnkrR3lTbm56U3YvQXBBTW96VUgzVUhuK1Z4VURGKzczUi9hNHdDeTJ5Y2pBTmxhc2owZ2hkSGlDemtUSnYvVXh5dDNkaDN3TjZCTk8ycTdHRHVsOFg2b2NQWCtpOWxqeDNjNkk3cS85MkhhSklSb0hwTnZvZVFyZmJEUllwbG9UVnpCYVNTRzZxOXNJcmduOVc4aURtM3NtRFo3STlmWjJvSjlWTU5ITzg0VUg1NGhOTEZzME9SNFNhVWJRWjRJK3pGMFA4Q3UvcHBnWHdaYXZpa2FUNkx6Z3RNQjEzTFJEOHZoaHRvazc1c1UrYlRuUmdKcDg3ZEY4cjNtZlBLRTRBZjNYK0lPTXZJTzQ5dU8ybDdVS015bWJKT0tjTWYyRlBzclpiamdsNmtpeUZnRjlwVGJXUmdOMXdTUkFHRWloVjBMR0JlTE5YcmhxVHdoNzFHbDZ0YmFHZ1VLQXU1QnpkM1FqUTNMTnhYb3VKeDVGbnhNSkdkNXFSMXQybjRGL3pyZXRLR0ZTc0xHZ0JvbTJCNnAzQzE0cW1WTndIK0trY05HV1gxS09NRktadnFCSDR2YzBoWmRiUGZiWXFQNjcwWmZhaDZQRm1UbzNxc21pV1p5WDlabm1UWGQzanc1SGlrZXB1bDVDWXQvUis3elN2SVFDbm1DSVE5Z0d4YW1sa2hsSkZJb1h0MTFpck5BdDR0d0lZOW1Pa2RDVzNySWpXWmUwOUFhQmFSVUpaOFQ3WlhOQldNMkExeDIvMjZHeXdnNjdMYWdiQUhUSEFBUlhUVTdBMThRRmh1ekJMYWZ2YTJkNlg0cmFCdnU2WEpwcXlPOVZYcGNhNkZDd051S3lGZmo0eHV0ZE42NW8xRm5aRWpoQnNKNnNlSGFad1MzOHNkdWtER0xQTFN5Z3lmRERsZnZWWE5CZEJneVRlMDd2VmNPMjloK0g5eCswZUVJTS9CRkFweHc5RUh6K1JocGN6clc1JmZtL3JhRE1sc0NMTFlpMVErRGtPcllvTGdldz0=; _ir=0' 50 | } 51 | }).then(({ data }) => { 52 | const $ = cheerio.load(data) 53 | const result = []; 54 | const hasil = []; 55 | $('div > a').get().map(b => { 56 | const link = $(b).find('img').attr('src') 57 | result.push(link) 58 | }); 59 | result.forEach(v => { 60 | if(v == undefined) return 61 | hasil.push(v.replace(/236/g,'736')) 62 | }) 63 | hasil.shift(); 64 | resolve(hasil) 65 | }) 66 | }); 67 | } 68 | 69 | async function pinterest2(query) { 70 | return new Promise(async (resolve, reject) => { 71 | const baseUrl = 'https://www.pinterest.com/resource/BaseSearchResource/get/'; 72 | const queryParams = { 73 | source_url: '/search/pins/?q=' + encodeURIComponent(query), 74 | data: JSON.stringify({ 75 | options: { 76 | isPrefetch: false, 77 | query, 78 | scope: 'pins', 79 | no_fetch_context_on_resource: false 80 | }, 81 | context: {} 82 | }), 83 | _: Date.now() 84 | }; 85 | const url = new URL(baseUrl); 86 | Object.entries(queryParams).forEach(entry => url.searchParams.set(entry[0], entry[1])); 87 | try { 88 | const json = await (await fetch(url.toString())).json(); 89 | const results = json.resource_response?.data?.results?? []; 90 | const result = results.map(item => ({ 91 | pin: 'https://www.pinterest.com/pin/' + item.id?? '', 92 | link: item.link?? '', 93 | created_at: (new Date(item.created_at)).toLocaleDateString('id-ID', { 94 | day: 'numeric', 95 | month: 'long', 96 | year: 'numeric' 97 | }) ?? '', 98 | id: item.id?? '', 99 | images_url: item.images?.['736x']?.url?? '', 100 | grid_title: item.grid_title?? '' 101 | })); 102 | resolve(result); 103 | } catch (e) { 104 | reject([]) 105 | } 106 | }); 107 | } 108 | 109 | async function remini(input, method) { 110 | return new Promise(async (resolve, reject) => { 111 | let Methods = ["enhance", "recolor", "dehaze"]; 112 | method = Methods.includes(method) ? method : Methods[0]; 113 | try { 114 | let buffer; 115 | if (typeof input === 'string') { 116 | try { 117 | const response = await axios.get(input, { responseType: 'arraybuffer' }); 118 | buffer = Buffer.from(response.data, 'binary'); 119 | } catch (error) { 120 | reject(error); 121 | } 122 | } else if (Buffer.isBuffer(input)) { 123 | buffer = input; 124 | } else { 125 | reject(new Error('Input tidak valid. Harap berikan URL atau buffer gambar.')); 126 | } 127 | let Form = new FormData(); 128 | let scheme = "https://inferenceengine.vyro.ai/" + method; 129 | Form.append("model_version", 1); 130 | Form.append("image", buffer, { 131 | filename: "enhance_image_body.jpg", 132 | contentType: "image/jpeg", 133 | }); 134 | Form.submit( 135 | { 136 | host: "inferenceengine.vyro.ai", 137 | path: "/" + method, 138 | protocol: "https:", 139 | headers: { 140 | "User-Agent": "okhttp/4.9.3", 141 | Connection: "Keep-Alive", 142 | "Accept-Encoding": "gzip", 143 | }, 144 | }, 145 | function (err, res) { 146 | if (err) reject(err); 147 | let data = []; 148 | res 149 | .on("data", function (chunk) { 150 | data.push(chunk); 151 | }) 152 | .on("end", () => { 153 | resolve(Buffer.concat(data)); 154 | }); 155 | res.on("error", (e) => { 156 | reject(e); 157 | }); 158 | } 159 | ); 160 | } catch (error) { 161 | reject(error); 162 | } 163 | }); 164 | } 165 | 166 | async function styletext(teks) { 167 | return new Promise(async (resolve, reject) => { 168 | axios.get('http://qaz.wtf/u/convert.cgi?text=' + teks).then(({ data }) => { 169 | let $ = cheerio.load(data) 170 | let hasil = [] 171 | $('table > tbody > tr').each(function (a, b) { 172 | hasil.push({ name: $(b).find('td:nth-child(1) > span').text(), result: $(b).find('td:nth-child(2)').text().trim() }) 173 | }); 174 | resolve(hasil) 175 | }); 176 | }); 177 | } 178 | 179 | async function ringtone(title) { 180 | return new Promise(async (resolve, reject) => { 181 | axios.get('https://meloboom.com/en/search/' + title).then(({ data }) => { 182 | let $ = cheerio.load(data) 183 | let hasil = [] 184 | $('#__next > main > section > div.jsx-2244708474.container > div > div > div > div:nth-child(4) > div > div > div > ul > li').each(function (a, b) { 185 | hasil.push({ title: $(b).find('h4').text(), source: 'https://meloboom.com/'+$(b).find('a').attr('href'), audio: $(b).find('audio').attr('src') }) 186 | }); 187 | resolve(hasil) 188 | }); 189 | }); 190 | } 191 | 192 | async function multiDownload(url) { 193 | return new Promise(async (resolve, reject) => { 194 | try { 195 | const timeout = 60000; 196 | const startTime = Date.now(); 197 | const headers = { 198 | 'Content-Type': 'application/json', 199 | 'Origin': 'https://publer.io', 200 | 'Referer': 'https://publer.io/', 201 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36', 202 | } 203 | const { data } = await axios.post('https://app.publer.io/hooks/media', { url, iphone: false }, { headers }); 204 | while (true) { 205 | if (Date.now() - startTime >= timeout) { 206 | reject(new Error('Loop Undefined')) 207 | break 208 | } 209 | const { data: res } = await axios.get('https://app.publer.io/api/v1/job_status/' + data.job_id, { headers }); 210 | if (res.status == 'complete') { 211 | resolve(res.payload) 212 | break 213 | } 214 | } 215 | } catch (e) { 216 | reject(e) 217 | } 218 | }); 219 | } 220 | 221 | async function wallpaper(title, page = '1') { 222 | return new Promise(async (resolve, reject) => { 223 | try { 224 | const { data } = await axios.get(`https://www.besthdwallpaper.com/search?CurrentPage=${page}&q=${title}`); 225 | const $ = cheerio.load(data); 226 | const hasil = []; 227 | $('div.grid-item').each(function (a, b) { 228 | hasil.push({ 229 | title: $(b).find('div.info > p').attr('title'), 230 | type: $(b).find('div.info > a:nth-child(2)').text(), 231 | source: 'https://www.besthdwallpaper.com' + $(b).find('a').attr('href'), 232 | image: [ 233 | $(b).find('picture > img').attr('data-src') || $(b).find('picture > img').attr('src'), 234 | $(b).find('picture > source:nth-child(1)').attr('srcset'), 235 | $(b).find('picture > source:nth-child(2)').attr('srcset') 236 | ] 237 | }); 238 | }); 239 | resolve(hasil) 240 | } catch (e) { 241 | reject(e) 242 | } 243 | }); 244 | } 245 | 246 | async function wikimedia(title) { 247 | return new Promise(async (resolve, reject) => { 248 | axios.get(`https://commons.wikimedia.org/w/index.php?search=${title}&title=Special:MediaSearch&go=Go&type=image`).then(({ data }) => { 249 | let $ = cheerio.load(data) 250 | let hasil = [] 251 | $('.sdms-search-results__list-wrapper > div > a').each(function (a, b) { 252 | hasil.push({ title: $(b).find('img').attr('alt'), source: $(b).attr('href'), image: $(b).find('img').attr('data-src') || $(b).find('img').attr('src') }) 253 | }); 254 | resolve(hasil) 255 | }); 256 | }); 257 | } 258 | 259 | async function quotesAnime() { 260 | try { 261 | const page = Math.floor(Math.random() * 184); 262 | const { data } = await axios.get('https://otakotaku.com/quote/feed/' + page); 263 | const $ = cheerio.load(data); 264 | const hasil = []; 265 | $('div.kotodama-list').each((l, h) => { 266 | hasil.push({ 267 | link: $(h).find('a').attr('href'), 268 | gambar: $(h).find('img').attr('data-src'), 269 | karakter: $(h).find('div.char-name').text().trim(), 270 | anime: $(h).find('div.anime-title').text().trim(), 271 | episode: $(h).find('div.meta').text(), 272 | up_at: $(h).find('small.meta').text(), 273 | quotes: $(h).find('div.quote').text().trim() 274 | }); 275 | }); 276 | return hasil; 277 | } catch (error) { 278 | throw error; 279 | } 280 | } 281 | 282 | async function happymod(query) { 283 | try { 284 | const baseUrl = 'https://www.happymod.com/'; 285 | const res = await axios.get(baseUrl + 'search.html?q=' + query); 286 | const $ = cheerio.load(res.data); 287 | const hasil = []; 288 | $("div.pdt-app-box").each((c, d) => { 289 | const title = $(d).find("a").text().trim(); 290 | const icon = $(d).find("img.lazy").attr('data-original'); 291 | const rating = $(d).find("span").text(); 292 | const link = baseUrl + $(d).find("a").attr('href'); 293 | hasil.push({ 294 | title, 295 | icon, 296 | link, 297 | rating 298 | }); 299 | }); 300 | return hasil; 301 | } catch (error) { 302 | throw error; 303 | } 304 | } 305 | 306 | async function umma(url) { 307 | try { 308 | const res = await axios.get(url); 309 | const $ = cheerio.load(res.data); 310 | const image = []; 311 | $('#article-content > div').find('img').each((a, b) => { 312 | image.push($(b).attr('src')); 313 | }); 314 | const hasil = { 315 | title: $('#wrap > div.content-container.font-6-16 > h1').text().trim(), 316 | author: { 317 | name: $('#wrap > div.content-container.font-6-16 > div.content-top > div > div.user-ame.font-6-16.fw').text().trim(), 318 | profilePic: $('#wrap > div.content-container.font-6-16 > div.content-top > div > div.profile-photo > img.photo').attr('src') 319 | }, 320 | caption: $('#article-content > div > p').text().trim(), 321 | media: $('#article-content > div > iframe').attr('src') ? [$('#article-content > div > iframe').attr('src')] : image, 322 | type: $('#article-content > div > iframe').attr('src') ? 'video' : 'image', 323 | like: $('#wrap > div.bottom-btns > div > button:nth-child(1) > div.text.font-6-12').text() 324 | }; 325 | return hasil; 326 | } catch (error) { 327 | throw error; 328 | } 329 | } 330 | 331 | async function jadwalsholat(query) { 332 | try { 333 | const { data } = await axios.get(`https://umrotix.com/jadwal-sholat/${query}`); 334 | const $ = cheerio.load(data); 335 | let result; 336 | $('body > div > div.main-wrapper.scrollspy-action > div:nth-child(3)').each((a, b) => { 337 | result = { 338 | tanggal: $(b).find('> div:nth-child(2)').text(), 339 | imsyak: $(b).find('> div.panel.daily > div > div > div > div > div:nth-child(1) > p:nth-child(2)').text(), 340 | subuh: $(b).find('> div.panel.daily > div > div > div > div > div:nth-child(2) > p:nth-child(2)').text(), 341 | dzuhur: $(b).find('> div.panel.daily > div > div > div > div > div:nth-child(3) > p:nth-child(2)').text(), 342 | ashar: $(b).find('> div.panel.daily > div > div > div > div > div:nth-child(4) > p:nth-child(2)').text(), 343 | maghrib: $(b).find('> div.panel.daily > div > div > div > div > div:nth-child(5) > p:nth-child(2)').text(), 344 | isya: $(b).find('> div.panel.daily > div > div > div > div > div:nth-child(6) > p:nth-child(2)').text() 345 | }; 346 | }); 347 | return result; 348 | } catch (error) { 349 | throw error; 350 | } 351 | } 352 | 353 | async function tiktokDl(url) { 354 | return new Promise(async (resolve, reject) => { 355 | try { 356 | let data = [] 357 | function formatNumber(integer) { 358 | let numb = parseInt(integer) 359 | return Number(numb).toLocaleString().replace(/,/g, '.') 360 | } 361 | 362 | function formatDate(n, locale = 'en') { 363 | let d = new Date(n) 364 | return d.toLocaleDateString(locale, { 365 | weekday: 'long', 366 | day: 'numeric', 367 | month: 'long', 368 | year: 'numeric', 369 | hour: 'numeric', 370 | minute: 'numeric', 371 | second: 'numeric' 372 | }) 373 | } 374 | 375 | let domain = 'https://www.tikwm.com/api/'; 376 | let res = await (await axios.post(domain, {}, { 377 | headers: { 378 | 'Accept': 'application/json, text/javascript, */*; q=0.01', 379 | 'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7', 380 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 381 | 'Origin': 'https://www.tikwm.com', 382 | 'Referer': 'https://www.tikwm.com/', 383 | 'Sec-Ch-Ua': '"Not)A;Brand" ;v="24" , "Chromium" ;v="116"', 384 | 'Sec-Ch-Ua-Mobile': '?1', 385 | 'Sec-Ch-Ua-Platform': 'Android', 386 | 'Sec-Fetch-Dest': 'empty', 387 | 'Sec-Fetch-Mode': 'cors', 388 | 'Sec-Fetch-Site': 'same-origin', 389 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36', 390 | 'X-Requested-With': 'XMLHttpRequest' 391 | }, 392 | params: { 393 | url: url, 394 | count: 12, 395 | cursor: 0, 396 | web: 1, 397 | hd: 1 398 | } 399 | })).data.data 400 | if (res && !res.size && !res.wm_size && !res.hd_size) { 401 | res.images.map(v => { 402 | data.push({ type: 'photo', url: v }) 403 | }) 404 | } else { 405 | if (res && res.wmplay) { 406 | data.push({ type: 'watermark', url: 'https://www.tikwm.com' + res.wmplay }) 407 | } 408 | if (res && res.play) { 409 | data.push({ type: 'nowatermark', url: 'https://www.tikwm.com' + res.play }) 410 | } 411 | if (res && res.hdplay) { 412 | data.push({ type: 'nowatermark_hd', url: 'https://www.tikwm.com' + res.hdplay }) 413 | } 414 | } 415 | let json = { 416 | status: true, 417 | title: res.title, 418 | taken_at: formatDate(res.create_time).replace('1970', ''), 419 | region: res.region, 420 | id: res.id, 421 | durations: res.duration, 422 | duration: res.duration + ' Seconds', 423 | cover: 'https://www.tikwm.com' + res.cover, 424 | size_wm: res.wm_size, 425 | size_nowm: res.size, 426 | size_nowm_hd: res.hd_size, 427 | data: data, 428 | music_info: { 429 | id: res.music_info.id, 430 | title: res.music_info.title, 431 | author: res.music_info.author, 432 | album: res.music_info.album ? res.music_info.album : null, 433 | url: 'https://www.tikwm.com' + res.music || res.music_info.play 434 | }, 435 | stats: { 436 | views: formatNumber(res.play_count), 437 | likes: formatNumber(res.digg_count), 438 | comment: formatNumber(res.comment_count), 439 | share: formatNumber(res.share_count), 440 | download: formatNumber(res.download_count) 441 | }, 442 | author: { 443 | id: res.author.id, 444 | fullname: res.author.unique_id, 445 | nickname: res.author.nickname, 446 | avatar: 'https://www.tikwm.com' + res.author.avatar 447 | } 448 | } 449 | resolve(json) 450 | } catch (e) { 451 | reject(e) 452 | } 453 | }); 454 | } 455 | 456 | async function facebookDl(url) { 457 | return new Promise(async (resolve, reject) => { 458 | try { 459 | const { data } = await axios.post('https://getmyfb.com/process', new URLSearchParams({ 460 | id: decodeURIComponent(url), 461 | locale: 'en', 462 | }), { 463 | headers: { 464 | 'hx-current-url': 'https://getmyfb.com/', 465 | 'hx-request': 'true', 466 | 'hx-target': url.includes('share') ? '#private-video-downloader' : '#target', 467 | 'hx-trigger': 'form', 468 | 'hx-post': '/process', 469 | 'hx-swap': 'innerHTML', 470 | } 471 | }); 472 | const $ = cheerio.load(data); 473 | resolve({ 474 | caption: $('.results-item-text').length > 0 ? $('.results-item-text').text().trim() : '', 475 | preview: $('.results-item-image').attr('src') || '', 476 | results: $('.results-list-item').get().map(el => ({ 477 | quality: parseInt($(el).text().trim()) || '', 478 | type: $(el).text().includes('HD') ? 'HD' : 'SD', 479 | url: $(el).find('a').attr('href') || '', 480 | })) 481 | }); 482 | } catch (e) { 483 | reject(e); 484 | } 485 | }); 486 | } 487 | 488 | async function instaStory(name) { 489 | return new Promise(async (resolve, reject) => { 490 | try { 491 | const results = []; 492 | const formData = new FormData(); 493 | const key = await axios.get('https://storydownloader.app/en'); 494 | const $$ = cheerio.load(key.data); 495 | const cookie = key.headers['set-cookie'] 496 | const token = $$('input[name="_token"]').attr('value'); 497 | const headers = { 498 | accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 499 | cookie: cookie, 500 | origin: 'https://storydownloader.app', 501 | referer: 'https://storydownloader.app/en', 502 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36', 503 | 'X-CSRF-TOKEN': token 504 | }; 505 | formData.append('username', name); 506 | formData.append('_token', token); 507 | const res = await axios.post('https://storydownloader.app/request', formData, { 508 | headers: { 509 | ...headers, 510 | ...formData.getHeaders() 511 | } 512 | }); 513 | const $ = cheerio.load(res.data.html); 514 | const username = $('h3.card-title').text(); 515 | const profile_url = $('img.card-avatar').attr('src'); 516 | $('div.row > div').each(function () { 517 | const _ = $(this); 518 | const url = _.find('a').attr('href'); 519 | const thumbnail = _.find('img').attr('src'); 520 | const type = /video_dashinit\.mp4/i.test(url) ? 'video' : 'image'; 521 | if (thumbnail && url) { 522 | results.push({ 523 | thumbnail, 524 | url, 525 | type, 526 | }) 527 | } 528 | }); 529 | const data = { 530 | username, 531 | profile_url, 532 | results 533 | }; 534 | resolve(data) 535 | } catch (e) { 536 | reject(e) 537 | } 538 | }) 539 | } 540 | 541 | async function bk9Ai(query) { 542 | const teks = encodeURIComponent(query); 543 | const urls = ['https://bk9.fun/ai/gemini?q=','https://bk9.fun/ai/jeeves-chat?q=','https://bk9.fun/ai/jeeves-chat2?q=','https://bk9.fun/ai/mendable?q=','https://bk9.fun/ai/Aoyo?q=']; 544 | for (let url of urls) { 545 | try { 546 | const { data } = await axios.get(url + teks); 547 | return data 548 | } catch (e) { 549 | } 550 | } 551 | } 552 | 553 | async function ytMp4(url, options) { 554 | return new Promise(async(resolve, reject) => { 555 | ytdl.getInfo(url, options).then(async(getUrl) => { 556 | const audioPath = path.join('./database/sampah', `audio_${Date.now()}.mp4`); 557 | const videoPath = path.join('./database/sampah', `video_${Date.now()}.mp4`); 558 | const outputPath = path.join('./database/sampah', `output_${Date.now()}.mp4`); 559 | await new Promise((resolv, rejectt) => { 560 | ytdl(url, { format: ytdl.chooseFormat(getUrl.formats, { quality: 'highestaudio', filter: 'audioonly' })}).pipe(fs.createWriteStream(audioPath)).on('finish', resolv).on('error', rejectt); 561 | }) 562 | await new Promise((resolv, rejectt) => { 563 | ytdl(url, { format: ytdl.chooseFormat(getUrl.formats, { quality: 'highestvideo', filter: 'videoonly' })}).pipe(fs.createWriteStream(videoPath)).on('finish', resolv).on('error', rejectt); 564 | }) 565 | await new Promise((resolv, rejectt) => { 566 | exec(`ffmpeg -i ${videoPath} -i ${audioPath} -c:v copy -c:a aac ${outputPath}`, (error, stdout, stderr) => { 567 | if (error) { 568 | rejectt(new Error(`ffmpeg error: ${error.message}`)); 569 | return; 570 | } 571 | resolv(); 572 | }); 573 | }); 574 | let title = getUrl.videoDetails.title; 575 | let desc = getUrl.videoDetails.description; 576 | let views = getUrl.videoDetails.viewCount; 577 | let likes = getUrl.videoDetails.likes; 578 | let dislike = getUrl.videoDetails.dislikes; 579 | let channel = getUrl.videoDetails.ownerChannelName; 580 | let uploadDate = getUrl.videoDetails.uploadDate; 581 | let thumb = getUrl.player_response.microformat.playerMicroformatRenderer.thumbnail.thumbnails[0].url; 582 | let result = fs.readFileSync(outputPath); 583 | await fs.promises.unlink(audioPath); 584 | await fs.promises.unlink(videoPath); 585 | await fs.promises.unlink(outputPath); 586 | resolve({ 587 | title, 588 | result, 589 | thumb, 590 | views, 591 | likes, 592 | dislike, 593 | channel, 594 | uploadDate, 595 | desc 596 | }); 597 | }).catch(reject); 598 | }); 599 | }; 600 | 601 | async function ytMp3(url, options) { 602 | return new Promise((resolve, reject) => { 603 | ytdl.getInfo(url, options).then(async(getUrl) => { 604 | let result = []; 605 | for(let i = 0; i < getUrl.formats.length; i++) { 606 | let item = getUrl.formats[i]; 607 | if (item.mimeType == 'audio/webm; codecs=\"opus\"') { 608 | let { contentLength } = item; 609 | let bytes = await bytesToSize(contentLength); 610 | result[i] = { 611 | audio: item.url, 612 | size: bytes 613 | }; 614 | }; 615 | }; 616 | let resultFix = result.filter(x => x.audio != undefined && x.size != undefined) 617 | let title = getUrl.videoDetails.title; 618 | let desc = getUrl.videoDetails.description; 619 | let views = getUrl.videoDetails.viewCount; 620 | let likes = getUrl.videoDetails.likes; 621 | let dislike = getUrl.videoDetails.dislikes; 622 | let channel = getUrl.videoDetails.ownerChannelName; 623 | let uploadDate = getUrl.videoDetails.uploadDate; 624 | let thumb = getUrl.player_response.microformat.playerMicroformatRenderer.thumbnail.thumbnails[0].url; 625 | resolve({ 626 | title, 627 | result: resultFix[0].audio, 628 | size: resultFix[0].size, 629 | thumb, 630 | views, 631 | likes, 632 | dislike, 633 | channel, 634 | uploadDate, 635 | desc 636 | }); 637 | }).catch(reject); 638 | }); 639 | } 640 | 641 | async function quotedLyo(teks, name, profile, reply, color = '#FFFFFF') { 642 | return new Promise(async (resolve, reject) => { 643 | const { url, options } = reply || {} 644 | const str = { 645 | type: 'quote', 646 | format: 'png', 647 | backgroundColor: color, 648 | width: 512, 649 | height: 768, 650 | scale: 2, 651 | messages: [{ 652 | entities: [], 653 | ...(url ? { media: { url }} : {}), 654 | avatar: true, 655 | from: { 656 | id: 1, 657 | name, 658 | photo: { 659 | url: profile 660 | } 661 | }, 662 | ...(options ? options : {}), 663 | text: teks, 664 | replyMessage: {} 665 | }] 666 | }; 667 | 668 | try { 669 | const { data } = await axios.post('https://bot.lyo.su/quote/generate', JSON.stringify(str, null, 2), { 670 | headers: { 671 | 'Content-Type': 'application/json' 672 | } 673 | }); 674 | resolve(data) 675 | } catch (e) { 676 | reject(e) 677 | } 678 | }); 679 | } 680 | 681 | async function yanzGpt(query, prompt = '') { 682 | return new Promise(async (resolve, reject) => { 683 | try { // Ai by Yanz-Gpt > https://whatsapp.com/channel/0029Vai7FxK5Ui2TkgHi1P0I 684 | const { data } = await axios.post('https://yanzgpt.my.id/chat', { 685 | messages: [{ role: 'system', content: prompt }, { role: 'user', content: query }], 686 | model: 'yanzgpt-revolution-25b-v3.0' 687 | }, { 688 | headers: { 689 | authorization: 'Bearer yzgpt-sc4tlKsMRdNMecNy', 690 | 'content-type': 'application/json' 691 | } 692 | }) 693 | resolve(data) 694 | } catch (e) { 695 | reject(e) 696 | } 697 | }) 698 | } 699 | 700 | async function simi(query) { 701 | return new Promise(async (resolve, reject) => { 702 | try { 703 | const isi = new URLSearchParams(); 704 | isi.append('text', query); 705 | isi.append('lc', 'id'); 706 | isi.append('=', ''); 707 | const { data } = await axios.post('https://simsimi.vn/web/simtalk', isi, { 708 | headers: { 709 | 'Accept': 'application/json, text/javascript, */*; q=0.01', 710 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 711 | 'X-Requested-With': 'XMLHttpRequest' 712 | } 713 | }); 714 | resolve(data) 715 | } catch (e) { 716 | reject(e) 717 | } 718 | }) 719 | } 720 | 721 | module.exports = { pinterest, pinterest2, wallpaper, remini, wikimedia, quotesAnime, multiDownload, yanzGpt, happymod, mediafireDl, umma, ringtone, jadwalsholat, styletext, tiktokDl, facebookDl, instaStory, bk9Ai, ytMp4, ytMp3, quotedLyo, simi } 722 | -------------------------------------------------------------------------------- /lib/sychyy.js: -------------------------------------------------------------------------------- 1 | [{ 2 | nameBot: "sychyyBotz", 3 | nameown: "yudaD0yy" 4 | }] 5 | -------------------------------------------------------------------------------- /lib/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/tictactoe.js: -------------------------------------------------------------------------------- 1 | class TicTacToe { 2 | constructor(playerX = 'x', playerO = 'o') { 3 | this.playerX = playerX 4 | this.playerO = playerO 5 | this._currentTurn = false 6 | this._x = 0 7 | this._o = 0 8 | this.turns = 0 9 | } 10 | 11 | get board() { 12 | return this._x | this._o 13 | } 14 | 15 | get currentTurn() { 16 | return this._currentTurn ? this.playerO : this.playerX 17 | } 18 | 19 | get enemyTurn() { 20 | return this._currentTurn ? this.playerX : this.playerO 21 | } 22 | 23 | static check(state) { 24 | for (let combo of [7, 56, 73, 84, 146, 273, 292, 448]) 25 | if ((state & combo) === combo) 26 | return !0 27 | return !1 28 | } 29 | 30 | /** 31 | * ```js 32 | * TicTacToe.toBinary(1, 2) // 0b010000000 33 | * ``` 34 | */ 35 | static toBinary(x = 0, y = 0) { 36 | if (x < 0 || x > 2 || y < 0 || y > 2) throw new Error('invalid position') 37 | return 1 << x + (3 * y) 38 | } 39 | 40 | /** 41 | * @param player `0` is `X`, `1` is `O` 42 | * 43 | * - `-3` `Game Ended` 44 | * - `-2` `Invalid` 45 | * - `-1` `Invalid Position` 46 | * - ` 0` `Position Occupied` 47 | * - ` 1` `Sucess` 48 | * @returns {-3|-2|-1|0|1} 49 | */ 50 | turn(player = 0, x = 0, y) { 51 | if (this.board === 511) return -3 52 | let pos = 0 53 | if (y == null) { 54 | if (x < 0 || x > 8) return -1 55 | pos = 1 << x 56 | } else { 57 | if (x < 0 || x > 2 || y < 0 || y > 2) return -1 58 | pos = TicTacToe.toBinary(x, y) 59 | } 60 | if (this._currentTurn ^ player) return -2 61 | if (this.board & pos) return 0 62 | this[this._currentTurn ? '_o' : '_x'] |= pos 63 | this._currentTurn = !this._currentTurn 64 | this.turns++ 65 | return 1 66 | } 67 | 68 | /** 69 | * @returns {('X'|'O'|1|2|3|4|5|6|7|8|9)[]} 70 | */ 71 | static render(boardX = 0, boardO = 0) { 72 | let x = parseInt(boardX.toString(2), 4) 73 | let y = parseInt(boardO.toString(2), 4) * 2 74 | return [...(x + y).toString(4).padStart(9, '0')].reverse().map((value, index) => value == 1 ? 'X' : value == 2 ? 'O' : ++index) 75 | } 76 | 77 | /** 78 | * @returns {('X'|'O'|1|2|3|4|5|6|7|8|9)[]} 79 | */ 80 | render() { 81 | return TicTacToe.render(this._x, this._o) 82 | } 83 | 84 | get winner() { 85 | let x = TicTacToe.check(this._x) 86 | let o = TicTacToe.check(this._o) 87 | return x ? this.playerX : o ? this.playerO : false 88 | } 89 | } 90 | 91 | new TicTacToe().turn 92 | 93 | module.exports = TicTacToe -------------------------------------------------------------------------------- /lib/tts.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path'); 2 | const gtts = require('node-gtts'); 3 | const { readFileSync, unlinkSync } = require('fs'); 4 | 5 | function tts(text, lang = 'id') { 6 | return new Promise((resolve, reject) => { 7 | try { 8 | let tts = gtts(lang) 9 | let filePath = join(__dirname, '../database/sampah', (1 * new Date) + '.wav') 10 | tts.save(filePath, text, () => { 11 | resolve(readFileSync(filePath)) 12 | unlinkSync(filePath) 13 | }) 14 | } catch (e) { reject(e) } 15 | }) 16 | } 17 | 18 | module.exports = { tts } -------------------------------------------------------------------------------- /lib/uploader.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const axios = require('axios'); 3 | const cheerio = require('cheerio'); 4 | const fetch = require('node-fetch'); 5 | const FormData = require('form-data'); 6 | const { fromBuffer } = require('file-type'); 7 | 8 | async function TelegraPh(buffer) { 9 | return new Promise (async (resolve, reject) => { 10 | try { 11 | const form = new FormData(); 12 | const input = Buffer.from(buffer); 13 | const { ext } = await fromBuffer(buffer); 14 | form.append('file', input, { filename: 'data.' + ext }); 15 | const data = await axios.post('https://telegra.ph/upload', form, { 16 | headers: { 17 | ...form.getHeaders() 18 | } 19 | }) 20 | resolve('https://telegra.ph' + data.data[0].src) 21 | } catch (e) { 22 | reject(e) 23 | } 24 | }) 25 | } 26 | 27 | async function UguuSe(buffer) { 28 | return new Promise (async (resolve, reject) => { 29 | try { 30 | const form = new FormData(); 31 | const input = Buffer.from(buffer); 32 | const { ext } = await fromBuffer(buffer); 33 | form.append('files[]', input, { filename: 'data.' + ext }); 34 | const data = await axios.post('https://uguu.se/upload.php', form, { 35 | headers: { 36 | ...form.getHeaders() 37 | } 38 | }) 39 | resolve(data.data.files[0]) 40 | } catch (e) { 41 | reject(e) 42 | } 43 | }) 44 | } 45 | 46 | async function webp2mp4File(path) { 47 | return new Promise((resolve, reject) => { 48 | const form = new FormData(); 49 | form.append('new-image-url', '') 50 | form.append('new-image', fs.createReadStream(path)) 51 | axios({ 52 | method: 'post', 53 | url: 'https://s6.ezgif.com/webp-to-mp4', 54 | data: form, 55 | headers: { 56 | 'Content-Type': `multipart/form-data; boundary=${form._boundary}` 57 | } 58 | }).then(({ data }) => { 59 | const FormDataThen = new FormData() 60 | const $ = cheerio.load(data) 61 | const file = $('input[name="file"]').attr('value') 62 | FormDataThen.append('file', file) 63 | FormDataThen.append('convert', "Convert WebP to MP4!") 64 | axios({ 65 | method: 'post', 66 | url: 'https://ezgif.com/webp-to-mp4/' + file, 67 | data: FormDataThen, 68 | headers: { 69 | 'Content-Type': `multipart/form-data; boundary=${FormDataThen._boundary}` 70 | } 71 | }).then(({ data }) => { 72 | const $ = cheerio.load(data) 73 | const result = 'https:' + $('div#output > p.outfile > video > source').attr('src') 74 | resolve({ 75 | status: true, 76 | message: "Created By MRHRTZ", 77 | result: result 78 | }) 79 | }).catch(reject) 80 | }).catch(reject) 81 | }) 82 | } 83 | 84 | module.exports = { TelegraPh, UguuSe, webp2mp4File } 85 | -------------------------------------------------------------------------------- /node_modules.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/node_modules.zip -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "syche", 3 | "version": "1.0.3", 4 | "description": "Bot WhatsApp Using Lib Baileys Multi Device", 5 | "main": "start.js", 6 | "type": "commonjs", 7 | "scripts": { 8 | "start": "node start.js" 9 | }, 10 | "keywords": [ 11 | "whatsapp-bot", 12 | "baileys-md", 13 | "bot-wa", 14 | "multi-device" 15 | ], 16 | "author": "Nazedev", 17 | "license": "MIT", 18 | "dependencies": { 19 | "@hapi/boom": "^10.0.0", 20 | "@ibaraki-douji/pixivts": "^2.4.1", 21 | "@whiskeysockets/baileys": "^6.7.9", 22 | "aki-api": "npm:@aqul/akinator-api@1.0.1", 23 | "awesome-phonenumber": "^4.4.0", 24 | "axios": "^0.24.0", 25 | "chalk": "^4.1.2", 26 | "youtube-yts": "^2.0.0", 27 | "cheerio": "^1.0.0-rc.10", 28 | "child_process": "^1.0.2", 29 | "crypto": "^1.0.1", 30 | "didyoumean": "^1.2.2", 31 | "express": "^4.18.2", 32 | "btch-downloader": "^2.8.3", 33 | "figlet": "^1.8.0", 34 | "file-type": "^16.5.3", 35 | "filesize": "^10.0.7", 36 | "fluent-ffmpeg": "^2.1.2", 37 | "fs": "^0.0.1-security", 38 | "g-i-s": "^2.1.7", 39 | "gm": "^1.25.0", 40 | "googlethis": "^1.7.1", 41 | "https": "^1.0.0", 42 | "human-readable": "^0.2.1", 43 | "jimp": "^0.16.2", 44 | "jsdom": "^21.1.0", 45 | "lowdb": "^2.1.0", 46 | "md5": "^2.3.0", 47 | "moment-timezone": "^0.5.43", 48 | "mongoose": "^7.3.4", 49 | "ms": "^2.1.3", 50 | "node-cron": "^3.0.0", 51 | "node-fetch": "^2.6.1", 52 | "node-gtts": "^2.0.2", 53 | "node-webpmux": "^3.1.7", 54 | "os": "^0.1.2", 55 | "path": "^0.12.7", 56 | "pdfkit": "^0.13.0", 57 | "perf_hooks": "^0.0.1", 58 | "pino": "^8.8.0", 59 | "process": "^0.11.10", 60 | "qrcode-terminal": "^0.12.0", 61 | "qs": "^6.11.0", 62 | "sharp": "^0.33.5", 63 | "similarity": "^1.2.1", 64 | "translate-google-api": "^1.0.4", 65 | "util": "^0.12.5", 66 | "ws": "^8.13.0", 67 | "xmlhttprequest": "^1.8.0", 68 | "yargs": "^17.6.2", 69 | "yt-search": "^2.10.4", 70 | "ytdl-core": "npm:@distube/ytdl-core@latest" 71 | }, 72 | "directories": { 73 | "lib": "lib" 74 | }, 75 | "repository": { 76 | "type": "git", 77 | "url": "git+https://github.com/nazedev/hitori.git" 78 | }, 79 | "bugs": { 80 | "url": "https://github.com/nazedev/hitori/issues" 81 | }, 82 | "homepage": "https://github.com/nazedev/hitori#readme" 83 | } 84 | -------------------------------------------------------------------------------- /setown.js: -------------------------------------------------------------------------------- 1 | global.owner = ['62882008702155']; -------------------------------------------------------------------------------- /settings.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const chalk = require('chalk'); 3 | /* 4 | * Create By Sych 5 | * Follow https://github.com/sychdev 6 | * Whatsapp : https://whatsapp.com/channel/0029Vb0v3F71yT264EejzJ3e 7 | */ 8 | //~~~~~~~~~~~~< GLOBAL SETTINGS >~~~~~~~~~~~~\\ 9 | //settings owner di ./setown.js 10 | global.packname = 'SychBotz' 11 | global.owner = ["62882008702155"] 12 | global.botnum = ["6287862997267"] 13 | global.author = 'ydaa' 14 | global.owname = 'mzyda' 15 | global.botname = 'SYCHY BOTz' 16 | global.themeemoji = '🪀' 17 | global.f = '> ' 18 | global.n = '`' 19 | global.videoMenu = fs.readFileSync('./sychMedia/menu/sych.mp4'); 20 | global.listv = ['⛏', '●', '■', '✿', '▲', 'ଳ', 'ϟ', '✶', '➤', '✦', '✧', '△', '❀', '⋆𖦹', '□', '𖤓', 'ᨒ', '◇', '𖣂', '々', '〆', 'ᯓ★', '꩜', '✮'] 21 | global.emot = ['🌱', '🌻', '🌞', '❄️', '🌿', '💫', '⭐', '🍃', '🔥', '⚡', '🫧', '🌵', '🪺', '🪨', '🪵', '🌪️', '🍄'] 22 | global.tempatDB = 'database.json' 23 | global.pairing_code = true 24 | global.fake = { 25 | tmenu: 'https://i.ibb.co.com/7bVhfhb/3ed349054e5c77cfbebf58293d1e0df0.jpg', 26 | texz: `${botname}`, 27 | anonim: 'https://telegra.ph/file/95670d63378f7f4210f03.png', 28 | thumbnailUrl: 'https://i.ibb.co.com/3rqCPX6/fk.jpg', 29 | thumbnail: fs.readFileSync('./src/media/sych.png'), 30 | docs: fs.readFileSync('./src/media/fake.pdf'), 31 | listfakedocs: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/pdf'], 32 | } 33 | global.my = { 34 | yt: 'https://www.youtube.com/@sychyy00', 35 | gh: 'https://github.com/sychyy', 36 | gc: 'https://chat.whatsapp.com/GQ5Gp0eSeDS6dPBYeHE6kf', 37 | ch: '120363383347233294@newsletter', 38 | } 39 | global.limit = { 40 | free: 999, 41 | premium: 999, 42 | vip: 'VIP' 43 | } 44 | global.uang = { 45 | free: 100000, 46 | premium: 1000000, 47 | vip: 10000000 48 | } 49 | global.mess = { 50 | key0: 'Apikey mu telah habis silahkan kunjungi\nhttps://my.hitori.pw', 51 | owner: 'lu bkn owner', 52 | admin: 'lu bkn atmin', 53 | botAdmin: 'gw bkn atmin bro', 54 | group: 'cma buat grup aj', 55 | private: 'cm di prvt cht', 56 | prem: 'lu bkn user premium', 57 | wait: 'bentar duluu', 58 | error: 'eror bro!', 59 | done: 'udh lunas yh' 60 | } 61 | global.APIs = { 62 | hitori: 'https://my.hitori.pw/api', 63 | } 64 | global.APIKeys = { 65 | 'https://my.hitori.pw/api': 'htrkey-awokawok', 66 | } 67 | //~~~~~~~~~~~~~~~< PROCESS >~~~~~~~~~~~~~~~\\ 68 | let file = require.resolve(__filename) 69 | fs.watchFile(file, () => { 70 | fs.unwatchFile(file) 71 | console.log(chalk.redBright(`Update ${__filename}`)) 72 | delete require.cache[file] 73 | require(file) 74 | }); -------------------------------------------------------------------------------- /speed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2012 Matt Martz 4 | # All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | 18 | import csv 19 | import datetime 20 | import errno 21 | import math 22 | import os 23 | import platform 24 | import re 25 | import signal 26 | import socket 27 | import sys 28 | import threading 29 | import timeit 30 | import xml.parsers.expat 31 | 32 | try: 33 | import gzip 34 | GZIP_BASE = gzip.GzipFile 35 | except ImportError: 36 | gzip = None 37 | GZIP_BASE = object 38 | 39 | __version__ = '2.1.4b1' 40 | 41 | 42 | class FakeShutdownEvent(object): 43 | """Class to fake a threading.Event.isSet so that home of this module 44 | are not required to register their own threading.Event() 45 | """ 46 | 47 | @staticmethod 48 | def isSet(): 49 | "Dummy method to always return false""" 50 | return False 51 | 52 | is_set = isSet 53 | 54 | 55 | # Some global variables we use 56 | DEBUG = False 57 | _GLOBAL_DEFAULT_TIMEOUT = object() 58 | PY25PLUS = sys.version_info[:2] >= (2, 5) 59 | PY26PLUS = sys.version_info[:2] >= (2, 6) 60 | PY32PLUS = sys.version_info[:2] >= (3, 2) 61 | PY310PLUS = sys.version_info[:2] >= (3, 10) 62 | 63 | # Begin import game to handle Python 2 and Python 3 64 | try: 65 | import json 66 | except ImportError: 67 | try: 68 | import simplejson as json 69 | except ImportError: 70 | json = None 71 | 72 | try: 73 | import xml.etree.ElementTree as ET 74 | try: 75 | from xml.etree.ElementTree import _Element as ET_Element 76 | except ImportError: 77 | pass 78 | except ImportError: 79 | from xml.dom import minidom as DOM 80 | from xml.parsers.expat import ExpatError 81 | ET = None 82 | 83 | try: 84 | from urllib2 import (urlopen, Request, HTTPError, URLError, 85 | AbstractHTTPHandler, ProxyHandler, 86 | HTTPDefaultErrorHandler, HTTPRedirectHandler, 87 | HTTPErrorProcessor, OpenerDirector) 88 | except ImportError: 89 | from urllib.request import (urlopen, Request, HTTPError, URLError, 90 | AbstractHTTPHandler, ProxyHandler, 91 | HTTPDefaultErrorHandler, HTTPRedirectHandler, 92 | HTTPErrorProcessor, OpenerDirector) 93 | 94 | try: 95 | from httplib import HTTPConnection, BadStatusLine 96 | except ImportError: 97 | from http.client import HTTPConnection, BadStatusLine 98 | 99 | try: 100 | from httplib import HTTPSConnection 101 | except ImportError: 102 | try: 103 | from http.client import HTTPSConnection 104 | except ImportError: 105 | HTTPSConnection = None 106 | 107 | try: 108 | from httplib import FakeSocket 109 | except ImportError: 110 | FakeSocket = None 111 | 112 | try: 113 | from Queue import Queue 114 | except ImportError: 115 | from queue import Queue 116 | 117 | try: 118 | from urlparse import urlparse 119 | except ImportError: 120 | from urllib.parse import urlparse 121 | 122 | try: 123 | from urlparse import parse_qs 124 | except ImportError: 125 | try: 126 | from urllib.parse import parse_qs 127 | except ImportError: 128 | from cgi import parse_qs 129 | 130 | try: 131 | from hashlib import md5 132 | except ImportError: 133 | from md5 import md5 134 | 135 | try: 136 | from argparse import ArgumentParser as ArgParser 137 | from argparse import SUPPRESS as ARG_SUPPRESS 138 | PARSER_TYPE_INT = int 139 | PARSER_TYPE_STR = str 140 | PARSER_TYPE_FLOAT = float 141 | except ImportError: 142 | from optparse import OptionParser as ArgParser 143 | from optparse import SUPPRESS_HELP as ARG_SUPPRESS 144 | PARSER_TYPE_INT = 'int' 145 | PARSER_TYPE_STR = 'string' 146 | PARSER_TYPE_FLOAT = 'float' 147 | 148 | try: 149 | from cStringIO import StringIO 150 | BytesIO = None 151 | except ImportError: 152 | try: 153 | from StringIO import StringIO 154 | BytesIO = None 155 | except ImportError: 156 | from io import StringIO, BytesIO 157 | 158 | try: 159 | import __builtin__ 160 | except ImportError: 161 | import builtins 162 | from io import TextIOWrapper, FileIO 163 | 164 | class _Py3Utf8Output(TextIOWrapper): 165 | """UTF-8 encoded wrapper around stdout for py3, to override 166 | ASCII stdout 167 | """ 168 | def __init__(self, f, **kwargs): 169 | buf = FileIO(f.fileno(), 'w') 170 | super(_Py3Utf8Output, self).__init__( 171 | buf, 172 | encoding='utf8', 173 | errors='strict' 174 | ) 175 | 176 | def write(self, s): 177 | super(_Py3Utf8Output, self).write(s) 178 | self.flush() 179 | 180 | _py3_print = getattr(builtins, 'print') 181 | try: 182 | _py3_utf8_stdout = _Py3Utf8Output(sys.stdout) 183 | _py3_utf8_stderr = _Py3Utf8Output(sys.stderr) 184 | except OSError: 185 | # sys.stdout/sys.stderr is not a compatible stdout/stderr object 186 | # just use it and hope things go ok 187 | _py3_utf8_stdout = sys.stdout 188 | _py3_utf8_stderr = sys.stderr 189 | 190 | def to_utf8(v): 191 | """No-op encode to utf-8 for py3""" 192 | return v 193 | 194 | def print_(*args, **kwargs): 195 | """Wrapper function for py3 to print, with a utf-8 encoded stdout""" 196 | if kwargs.get('file') == sys.stderr: 197 | kwargs['file'] = _py3_utf8_stderr 198 | else: 199 | kwargs['file'] = kwargs.get('file', _py3_utf8_stdout) 200 | _py3_print(*args, **kwargs) 201 | else: 202 | del __builtin__ 203 | 204 | def to_utf8(v): 205 | """Encode value to utf-8 if possible for py2""" 206 | try: 207 | return v.encode('utf8', 'strict') 208 | except AttributeError: 209 | return v 210 | 211 | def print_(*args, **kwargs): 212 | """The new-style print function for Python 2.4 and 2.5. 213 | 214 | Taken from https://pypi.python.org/pypi/six/ 215 | 216 | Modified to set encoding to UTF-8 always, and to flush after write 217 | """ 218 | fp = kwargs.pop("file", sys.stdout) 219 | if fp is None: 220 | return 221 | 222 | def write(data): 223 | if not isinstance(data, basestring): 224 | data = str(data) 225 | # If the file has an encoding, encode unicode with it. 226 | encoding = 'utf8' # Always trust UTF-8 for output 227 | if (isinstance(fp, file) and 228 | isinstance(data, unicode) and 229 | encoding is not None): 230 | errors = getattr(fp, "errors", None) 231 | if errors is None: 232 | errors = "strict" 233 | data = data.encode(encoding, errors) 234 | fp.write(data) 235 | fp.flush() 236 | want_unicode = False 237 | sep = kwargs.pop("sep", None) 238 | if sep is not None: 239 | if isinstance(sep, unicode): 240 | want_unicode = True 241 | elif not isinstance(sep, str): 242 | raise TypeError("sep must be None or a string") 243 | end = kwargs.pop("end", None) 244 | if end is not None: 245 | if isinstance(end, unicode): 246 | want_unicode = True 247 | elif not isinstance(end, str): 248 | raise TypeError("end must be None or a string") 249 | if kwargs: 250 | raise TypeError("invalid keyword arguments to print()") 251 | if not want_unicode: 252 | for arg in args: 253 | if isinstance(arg, unicode): 254 | want_unicode = True 255 | break 256 | if want_unicode: 257 | newline = unicode("\n") 258 | space = unicode(" ") 259 | else: 260 | newline = "\n" 261 | space = " " 262 | if sep is None: 263 | sep = space 264 | if end is None: 265 | end = newline 266 | for i, arg in enumerate(args): 267 | if i: 268 | write(sep) 269 | write(arg) 270 | write(end) 271 | 272 | # Exception "constants" to support Python 2 through Python 3 273 | try: 274 | import ssl 275 | try: 276 | CERT_ERROR = (ssl.CertificateError,) 277 | except AttributeError: 278 | CERT_ERROR = tuple() 279 | 280 | HTTP_ERRORS = ( 281 | (HTTPError, URLError, socket.error, ssl.SSLError, BadStatusLine) + 282 | CERT_ERROR 283 | ) 284 | except ImportError: 285 | ssl = None 286 | HTTP_ERRORS = (HTTPError, URLError, socket.error, BadStatusLine) 287 | 288 | if PY32PLUS: 289 | etree_iter = ET.Element.iter 290 | elif PY25PLUS: 291 | etree_iter = ET_Element.getiterator 292 | 293 | if PY26PLUS: 294 | thread_is_alive = threading.Thread.is_alive 295 | else: 296 | thread_is_alive = threading.Thread.isAlive 297 | 298 | 299 | def event_is_set(event): 300 | try: 301 | return event.is_set() 302 | except AttributeError: 303 | return event.isSet() 304 | 305 | 306 | class SpeedtestException(Exception): 307 | """Base exception for this module""" 308 | 309 | 310 | class SpeedtestCLIError(SpeedtestException): 311 | """Generic exception for raising errors during CLI operation""" 312 | 313 | 314 | class SpeedtestHTTPError(SpeedtestException): 315 | """Base HTTP exception for this module""" 316 | 317 | 318 | class SpeedtestConfigError(SpeedtestException): 319 | """Configuration XML is invalid""" 320 | 321 | 322 | class SpeedtestServersError(SpeedtestException): 323 | """Servers XML is invalid""" 324 | 325 | 326 | class ConfigRetrievalError(SpeedtestHTTPError): 327 | """Could not retrieve config.php""" 328 | 329 | 330 | class ServersRetrievalError(SpeedtestHTTPError): 331 | """Could not retrieve speedtest-servers.php""" 332 | 333 | 334 | class InvalidServerIDType(SpeedtestException): 335 | """Server ID used for filtering was not an integer""" 336 | 337 | 338 | class NoMatchedServers(SpeedtestException): 339 | """No servers matched when filtering""" 340 | 341 | 342 | class SpeedtestMiniConnectFailure(SpeedtestException): 343 | """Could not connect to the provided speedtest mini server""" 344 | 345 | 346 | class InvalidSpeedtestMiniServer(SpeedtestException): 347 | """Server provided as a speedtest mini server does not actually appear 348 | to be a speedtest mini server 349 | """ 350 | 351 | 352 | class ShareResultsConnectFailure(SpeedtestException): 353 | """Could not connect to speedtest.net API to POST results""" 354 | 355 | 356 | class ShareResultsSubmitFailure(SpeedtestException): 357 | """Unable to successfully POST results to speedtest.net API after 358 | connection 359 | """ 360 | 361 | 362 | class SpeedtestUploadTimeout(SpeedtestException): 363 | """testlength configuration reached during upload 364 | Used to ensure the upload halts when no additional data should be sent 365 | """ 366 | 367 | 368 | class SpeedtestBestServerFailure(SpeedtestException): 369 | """Unable to determine best server""" 370 | 371 | 372 | class SpeedtestMissingBestServer(SpeedtestException): 373 | """get_best_server not called or not able to determine best server""" 374 | 375 | 376 | def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, 377 | source_address=None): 378 | """Connect to *address* and return the socket object. 379 | 380 | Convenience function. Connect to *address* (a 2-tuple ``(host, 381 | port)``) and return the socket object. Passing the optional 382 | *timeout* parameter will set the timeout on the socket instance 383 | before attempting to connect. If no *timeout* is supplied, the 384 | global default timeout setting returned by :fun`getdefaulttimeout` 385 | is used. If *source_address* is set it must be a tuple of (host, port) 386 | for the socket to bind as a source address before making the connection. 387 | An host of '' or port 0 tells the OS to use the default. 388 | 389 | Largely vendored from Python 2.7, modified to work with Python 2.4 390 | """ 391 | 392 | host, port = address 393 | err = None 394 | for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): 395 | af, socktype, proto, canonname, sa = res 396 | sock = None 397 | try: 398 | sock = socket.socket(af, socktype, proto) 399 | if timeout is not _GLOBAL_DEFAULT_TIMEOUT: 400 | sock.settimeout(float(timeout)) 401 | if source_address: 402 | sock.bind(source_address) 403 | sock.connect(sa) 404 | return sock 405 | 406 | except socket.error: 407 | err = get_exception() 408 | if sock is not None: 409 | sock.close() 410 | 411 | if err is not None: 412 | raise err 413 | else: 414 | raise socket.error("getaddrinfo returns an empty list") 415 | 416 | 417 | class SpeedtestHTTPConnection(HTTPConnection): 418 | """Custom HTTPConnection to support source_address across 419 | Python 2.4 - Python 3 420 | """ 421 | def __init__(self, *args, **kwargs): 422 | source_address = kwargs.pop('source_address', None) 423 | timeout = kwargs.pop('timeout', 10) 424 | 425 | self._tunnel_host = None 426 | 427 | HTTPConnection.__init__(self, *args, **kwargs) 428 | 429 | self.source_address = source_address 430 | self.timeout = timeout 431 | 432 | def connect(self): 433 | """Connect to the host and port specified in __init__.""" 434 | try: 435 | self.sock = socket.create_connection( 436 | (self.host, self.port), 437 | self.timeout, 438 | self.source_address 439 | ) 440 | except (AttributeError, TypeError): 441 | self.sock = create_connection( 442 | (self.host, self.port), 443 | self.timeout, 444 | self.source_address 445 | ) 446 | 447 | if self._tunnel_host: 448 | self._tunnel() 449 | 450 | 451 | if HTTPSConnection: 452 | class SpeedtestHTTPSConnection(HTTPSConnection): 453 | """Custom HTTPSConnection to support source_address across 454 | Python 2.4 - Python 3 455 | """ 456 | default_port = 443 457 | 458 | def __init__(self, *args, **kwargs): 459 | source_address = kwargs.pop('source_address', None) 460 | timeout = kwargs.pop('timeout', 10) 461 | 462 | self._tunnel_host = None 463 | 464 | HTTPSConnection.__init__(self, *args, **kwargs) 465 | 466 | self.timeout = timeout 467 | self.source_address = source_address 468 | 469 | def connect(self): 470 | "Connect to a host on a given (SSL) port." 471 | try: 472 | self.sock = socket.create_connection( 473 | (self.host, self.port), 474 | self.timeout, 475 | self.source_address 476 | ) 477 | except (AttributeError, TypeError): 478 | self.sock = create_connection( 479 | (self.host, self.port), 480 | self.timeout, 481 | self.source_address 482 | ) 483 | 484 | if self._tunnel_host: 485 | self._tunnel() 486 | 487 | if ssl: 488 | try: 489 | kwargs = {} 490 | if hasattr(ssl, 'SSLContext'): 491 | if self._tunnel_host: 492 | kwargs['server_hostname'] = self._tunnel_host 493 | else: 494 | kwargs['server_hostname'] = self.host 495 | self.sock = self._context.wrap_socket(self.sock, **kwargs) 496 | except AttributeError: 497 | self.sock = ssl.wrap_socket(self.sock) 498 | try: 499 | self.sock.server_hostname = self.host 500 | except AttributeError: 501 | pass 502 | elif FakeSocket: 503 | # Python 2.4/2.5 support 504 | try: 505 | self.sock = FakeSocket(self.sock, socket.ssl(self.sock)) 506 | except AttributeError: 507 | raise SpeedtestException( 508 | 'This version of Python does not support HTTPS/SSL ' 509 | 'functionality' 510 | ) 511 | else: 512 | raise SpeedtestException( 513 | 'This version of Python does not support HTTPS/SSL ' 514 | 'functionality' 515 | ) 516 | 517 | 518 | def _build_connection(connection, source_address, timeout, context=None): 519 | """Cross Python 2.4 - Python 3 callable to build an ``HTTPConnection`` or 520 | ``HTTPSConnection`` with the args we need 521 | 522 | Called from ``http(s)_open`` methods of ``SpeedtestHTTPHandler`` or 523 | ``SpeedtestHTTPSHandler`` 524 | """ 525 | def inner(host, **kwargs): 526 | kwargs.update({ 527 | 'source_address': source_address, 528 | 'timeout': timeout 529 | }) 530 | if context: 531 | kwargs['context'] = context 532 | return connection(host, **kwargs) 533 | return inner 534 | 535 | 536 | class SpeedtestHTTPHandler(AbstractHTTPHandler): 537 | """Custom ``HTTPHandler`` that can build a ``HTTPConnection`` with the 538 | args we need for ``source_address`` and ``timeout`` 539 | """ 540 | def __init__(self, debuglevel=0, source_address=None, timeout=10): 541 | AbstractHTTPHandler.__init__(self, debuglevel) 542 | self.source_address = source_address 543 | self.timeout = timeout 544 | 545 | def http_open(self, req): 546 | return self.do_open( 547 | _build_connection( 548 | SpeedtestHTTPConnection, 549 | self.source_address, 550 | self.timeout 551 | ), 552 | req 553 | ) 554 | 555 | http_request = AbstractHTTPHandler.do_request_ 556 | 557 | 558 | class SpeedtestHTTPSHandler(AbstractHTTPHandler): 559 | """Custom ``HTTPSHandler`` that can build a ``HTTPSConnection`` with the 560 | args we need for ``source_address`` and ``timeout`` 561 | """ 562 | def __init__(self, debuglevel=0, context=None, source_address=None, 563 | timeout=10): 564 | AbstractHTTPHandler.__init__(self, debuglevel) 565 | self._context = context 566 | self.source_address = source_address 567 | self.timeout = timeout 568 | 569 | def https_open(self, req): 570 | return self.do_open( 571 | _build_connection( 572 | SpeedtestHTTPSConnection, 573 | self.source_address, 574 | self.timeout, 575 | context=self._context, 576 | ), 577 | req 578 | ) 579 | 580 | https_request = AbstractHTTPHandler.do_request_ 581 | 582 | 583 | def build_opener(source_address=None, timeout=10): 584 | """Function similar to ``urllib2.build_opener`` that will build 585 | an ``OpenerDirector`` with the explicit handlers we want, 586 | ``source_address`` for binding, ``timeout`` and our custom 587 | `User-Agent` 588 | """ 589 | 590 | printer('Timeout set to %d' % timeout, debug=True) 591 | 592 | if source_address: 593 | source_address_tuple = (source_address, 0) 594 | printer('Binding to source address: %r' % (source_address_tuple,), 595 | debug=True) 596 | else: 597 | source_address_tuple = None 598 | 599 | handlers = [ 600 | ProxyHandler(), 601 | SpeedtestHTTPHandler(source_address=source_address_tuple, 602 | timeout=timeout), 603 | SpeedtestHTTPSHandler(source_address=source_address_tuple, 604 | timeout=timeout), 605 | HTTPDefaultErrorHandler(), 606 | HTTPRedirectHandler(), 607 | HTTPErrorProcessor() 608 | ] 609 | 610 | opener = OpenerDirector() 611 | opener.addheaders = [('User-agent', build_user_agent())] 612 | 613 | for handler in handlers: 614 | opener.add_handler(handler) 615 | 616 | return opener 617 | 618 | 619 | class GzipDecodedResponse(GZIP_BASE): 620 | """A file-like object to decode a response encoded with the gzip 621 | method, as described in RFC 1952. 622 | 623 | Largely copied from ``xmlrpclib``/``xmlrpc.client`` and modified 624 | to work for py2.4-py3 625 | """ 626 | def __init__(self, response): 627 | # response doesn't support tell() and read(), required by 628 | # GzipFile 629 | if not gzip: 630 | raise SpeedtestHTTPError('HTTP response body is gzip encoded, ' 631 | 'but gzip support is not available') 632 | IO = BytesIO or StringIO 633 | self.io = IO() 634 | while 1: 635 | chunk = response.read(1024) 636 | if len(chunk) == 0: 637 | break 638 | self.io.write(chunk) 639 | self.io.seek(0) 640 | gzip.GzipFile.__init__(self, mode='rb', fileobj=self.io) 641 | 642 | def close(self): 643 | try: 644 | gzip.GzipFile.close(self) 645 | finally: 646 | self.io.close() 647 | 648 | 649 | def get_exception(): 650 | """Helper function to work with py2.4-py3 for getting the current 651 | exception in a try/except block 652 | """ 653 | return sys.exc_info()[1] 654 | 655 | 656 | def distance(origin, destination): 657 | """Determine distance between 2 sets of [lat,lon] in km""" 658 | 659 | lat1, lon1 = origin 660 | lat2, lon2 = destination 661 | radius = 6371 # km 662 | 663 | dlat = math.radians(lat2 - lat1) 664 | dlon = math.radians(lon2 - lon1) 665 | a = (math.sin(dlat / 2) * math.sin(dlat / 2) + 666 | math.cos(math.radians(lat1)) * 667 | math.cos(math.radians(lat2)) * math.sin(dlon / 2) * 668 | math.sin(dlon / 2)) 669 | c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) 670 | d = radius * c 671 | 672 | return d 673 | 674 | 675 | def build_user_agent(): 676 | """Build a Mozilla/5.0 compatible User-Agent string""" 677 | 678 | ua_tuple = ( 679 | 'Mozilla/5.0', 680 | '(%s; U; %s; en-us)' % (platform.platform(), 681 | platform.architecture()[0]), 682 | 'Python/%s' % platform.python_version(), 683 | '(KHTML, like Gecko)', 684 | 'speedtest-cli/%s' % __version__ 685 | ) 686 | user_agent = ' '.join(ua_tuple) 687 | printer('User-Agent: %s' % user_agent, debug=True) 688 | return user_agent 689 | 690 | 691 | def build_request(url, data=None, headers=None, bump='0', secure=False): 692 | """Build a urllib2 request object 693 | 694 | This function automatically adds a User-Agent header to all requests 695 | 696 | """ 697 | 698 | if not headers: 699 | headers = {} 700 | 701 | if url[0] == ':': 702 | scheme = ('http', 'https')[bool(secure)] 703 | schemed_url = '%s%s' % (scheme, url) 704 | else: 705 | schemed_url = url 706 | 707 | if '?' in url: 708 | delim = '&' 709 | else: 710 | delim = '?' 711 | 712 | # WHO YOU GONNA CALL? CACHE BUSTERS! 713 | final_url = '%s%sx=%s.%s' % (schemed_url, delim, 714 | int(timeit.time.time() * 1000), 715 | bump) 716 | 717 | headers.update({ 718 | 'Cache-Control': 'no-cache', 719 | }) 720 | 721 | printer('%s %s' % (('GET', 'POST')[bool(data)], final_url), 722 | debug=True) 723 | 724 | return Request(final_url, data=data, headers=headers) 725 | 726 | 727 | def catch_request(request, opener=None): 728 | """Helper function to catch common exceptions encountered when 729 | establishing a connection with a HTTP/HTTPS request 730 | 731 | """ 732 | 733 | if opener: 734 | _open = opener.open 735 | else: 736 | _open = urlopen 737 | 738 | try: 739 | uh = _open(request) 740 | if request.get_full_url() != uh.geturl(): 741 | printer('Redirected to %s' % uh.geturl(), debug=True) 742 | return uh, False 743 | except HTTP_ERRORS: 744 | e = get_exception() 745 | return None, e 746 | 747 | 748 | def get_response_stream(response): 749 | """Helper function to return either a Gzip reader if 750 | ``Content-Encoding`` is ``gzip`` otherwise the response itself 751 | 752 | """ 753 | 754 | try: 755 | getheader = response.headers.getheader 756 | except AttributeError: 757 | getheader = response.getheader 758 | 759 | if getheader('content-encoding') == 'gzip': 760 | return GzipDecodedResponse(response) 761 | 762 | return response 763 | 764 | 765 | def get_attributes_by_tag_name(dom, tag_name): 766 | """Retrieve an attribute from an XML document and return it in a 767 | consistent format 768 | 769 | Only used with xml.dom.minidom, which is likely only to be used 770 | with python versions older than 2.5 771 | """ 772 | elem = dom.getElementsByTagName(tag_name)[0] 773 | return dict(list(elem.attributes.items())) 774 | 775 | 776 | def print_dots(shutdown_event): 777 | """Built in callback function used by Thread classes for printing 778 | status 779 | """ 780 | def inner(current, total, start=False, end=False): 781 | if event_is_set(shutdown_event): 782 | return 783 | 784 | sys.stdout.write('.') 785 | if current + 1 == total and end is True: 786 | sys.stdout.write('\n') 787 | sys.stdout.flush() 788 | return inner 789 | 790 | 791 | def do_nothing(*args, **kwargs): 792 | pass 793 | 794 | 795 | class HTTPDownloader(threading.Thread): 796 | """Thread class for retrieving a URL""" 797 | 798 | def __init__(self, i, request, start, timeout, opener=None, 799 | shutdown_event=None): 800 | threading.Thread.__init__(self) 801 | self.request = request 802 | self.result = [0] 803 | self.starttime = start 804 | self.timeout = timeout 805 | self.i = i 806 | if opener: 807 | self._opener = opener.open 808 | else: 809 | self._opener = urlopen 810 | 811 | if shutdown_event: 812 | self._shutdown_event = shutdown_event 813 | else: 814 | self._shutdown_event = FakeShutdownEvent() 815 | 816 | def run(self): 817 | try: 818 | if (timeit.default_timer() - self.starttime) <= self.timeout: 819 | f = self._opener(self.request) 820 | while (not event_is_set(self._shutdown_event) and 821 | (timeit.default_timer() - self.starttime) <= 822 | self.timeout): 823 | self.result.append(len(f.read(10240))) 824 | if self.result[-1] == 0: 825 | break 826 | f.close() 827 | except IOError: 828 | pass 829 | except HTTP_ERRORS: 830 | pass 831 | 832 | 833 | class HTTPUploaderData(object): 834 | """File like object to improve cutting off the upload once the timeout 835 | has been reached 836 | """ 837 | 838 | def __init__(self, length, start, timeout, shutdown_event=None): 839 | self.length = length 840 | self.start = start 841 | self.timeout = timeout 842 | 843 | if shutdown_event: 844 | self._shutdown_event = shutdown_event 845 | else: 846 | self._shutdown_event = FakeShutdownEvent() 847 | 848 | self._data = None 849 | 850 | self.total = [0] 851 | 852 | def pre_allocate(self): 853 | chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' 854 | multiplier = int(round(int(self.length) / 36.0)) 855 | IO = BytesIO or StringIO 856 | try: 857 | self._data = IO( 858 | ('content1=%s' % 859 | (chars * multiplier)[0:int(self.length) - 9] 860 | ).encode() 861 | ) 862 | except MemoryError: 863 | raise SpeedtestCLIError( 864 | 'Insufficient memory to pre-allocate upload data. Please ' 865 | 'use --no-pre-allocate' 866 | ) 867 | 868 | @property 869 | def data(self): 870 | if not self._data: 871 | self.pre_allocate() 872 | return self._data 873 | 874 | def read(self, n=10240): 875 | if ((timeit.default_timer() - self.start) <= self.timeout and 876 | not event_is_set(self._shutdown_event)): 877 | chunk = self.data.read(n) 878 | self.total.append(len(chunk)) 879 | return chunk 880 | else: 881 | raise SpeedtestUploadTimeout() 882 | 883 | def __len__(self): 884 | return self.length 885 | 886 | 887 | class HTTPUploader(threading.Thread): 888 | """Thread class for putting a URL""" 889 | 890 | def __init__(self, i, request, start, size, timeout, opener=None, 891 | shutdown_event=None): 892 | threading.Thread.__init__(self) 893 | self.request = request 894 | self.request.data.start = self.starttime = start 895 | self.size = size 896 | self.result = 0 897 | self.timeout = timeout 898 | self.i = i 899 | 900 | if opener: 901 | self._opener = opener.open 902 | else: 903 | self._opener = urlopen 904 | 905 | if shutdown_event: 906 | self._shutdown_event = shutdown_event 907 | else: 908 | self._shutdown_event = FakeShutdownEvent() 909 | 910 | def run(self): 911 | request = self.request 912 | try: 913 | if ((timeit.default_timer() - self.starttime) <= self.timeout and 914 | not event_is_set(self._shutdown_event)): 915 | try: 916 | f = self._opener(request) 917 | except TypeError: 918 | # PY24 expects a string or buffer 919 | # This also causes issues with Ctrl-C, but we will concede 920 | # for the moment that Ctrl-C on PY24 isn't immediate 921 | request = build_request(self.request.get_full_url(), 922 | data=request.data.read(self.size)) 923 | f = self._opener(request) 924 | f.read(11) 925 | f.close() 926 | self.result = sum(self.request.data.total) 927 | else: 928 | self.result = 0 929 | except (IOError, SpeedtestUploadTimeout): 930 | self.result = sum(self.request.data.total) 931 | except HTTP_ERRORS: 932 | self.result = 0 933 | 934 | 935 | class SpeedtestResults(object): 936 | """Class for holding the results of a speedtest, including: 937 | 938 | Download speed 939 | Upload speed 940 | Ping/Latency to test server 941 | Data about server that the test was run against 942 | 943 | Additionally this class can return a result data as a dictionary or CSV, 944 | as well as submit a POST of the result data to the speedtest.net API 945 | to get a share results image link. 946 | """ 947 | 948 | def __init__(self, download=0, upload=0, ping=0, server=None, client=None, 949 | opener=None, secure=False): 950 | self.download = download 951 | self.upload = upload 952 | self.ping = ping 953 | if server is None: 954 | self.server = {} 955 | else: 956 | self.server = server 957 | self.client = client or {} 958 | 959 | self._share = None 960 | self.timestamp = '%sZ' % datetime.datetime.now(datetime.timezone.utc).isoformat() 961 | self.bytes_received = 0 962 | self.bytes_sent = 0 963 | 964 | if opener: 965 | self._opener = opener 966 | else: 967 | self._opener = build_opener() 968 | 969 | self._secure = secure 970 | 971 | def __repr__(self): 972 | return repr(self.dict()) 973 | 974 | def share(self): 975 | """POST data to the speedtest.net API to obtain a share results 976 | link 977 | """ 978 | 979 | if self._share: 980 | return self._share 981 | 982 | download = int(round(self.download / 1000.0, 0)) 983 | ping = int(round(self.ping, 0)) 984 | upload = int(round(self.upload / 1000.0, 0)) 985 | 986 | # Build the request to send results back to speedtest.net 987 | # We use a list instead of a dict because the API expects parameters 988 | # in a certain order 989 | api_data = [ 990 | 'recommendedserverid=%s' % self.server['id'], 991 | 'ping=%s' % ping, 992 | 'screenresolution=', 993 | 'promo=', 994 | 'download=%s' % download, 995 | 'screendpi=', 996 | 'upload=%s' % upload, 997 | 'testmethod=http', 998 | 'hash=%s' % md5(('%s-%s-%s-%s' % 999 | (ping, upload, download, '297aae72')) 1000 | .encode()).hexdigest(), 1001 | 'touchscreen=none', 1002 | 'startmode=pingselect', 1003 | 'accuracy=1', 1004 | 'bytesreceived=%s' % self.bytes_received, 1005 | 'bytessent=%s' % self.bytes_sent, 1006 | 'serverid=%s' % self.server['id'], 1007 | ] 1008 | 1009 | headers = {'Referer': 'http://c.speedtest.net/flash/speedtest.swf'} 1010 | request = build_request('://www.speedtest.net/api/api.php', 1011 | data='&'.join(api_data).encode(), 1012 | headers=headers, secure=self._secure) 1013 | f, e = catch_request(request, opener=self._opener) 1014 | if e: 1015 | raise ShareResultsConnectFailure(e) 1016 | 1017 | response = f.read() 1018 | code = f.code 1019 | f.close() 1020 | 1021 | if int(code) != 200: 1022 | raise ShareResultsSubmitFailure('Could not submit results to ' 1023 | 'speedtest.net') 1024 | 1025 | qsargs = parse_qs(response.decode()) 1026 | resultid = qsargs.get('resultid') 1027 | if not resultid or len(resultid) != 1: 1028 | raise ShareResultsSubmitFailure('Could not submit results to ' 1029 | 'speedtest.net') 1030 | 1031 | self._share = 'http://www.speedtest.net/result/%s.png' % resultid[0] 1032 | 1033 | return self._share 1034 | 1035 | def dict(self): 1036 | """Return dictionary of result data""" 1037 | 1038 | return { 1039 | 'download': self.download, 1040 | 'upload': self.upload, 1041 | 'ping': self.ping, 1042 | 'server': self.server, 1043 | 'timestamp': self.timestamp, 1044 | 'bytes_sent': self.bytes_sent, 1045 | 'bytes_received': self.bytes_received, 1046 | 'share': self._share, 1047 | 'client': self.client, 1048 | } 1049 | 1050 | @staticmethod 1051 | def csv_header(delimiter=','): 1052 | """Return CSV Headers""" 1053 | 1054 | row = ['Server ID', 'Sponsor', 'Server Name', 'Timestamp', 'Distance', 1055 | 'Ping', 'Download', 'Upload', 'Share', 'IP Address'] 1056 | out = StringIO() 1057 | writer = csv.writer(out, delimiter=delimiter, lineterminator='') 1058 | writer.writerow([to_utf8(v) for v in row]) 1059 | return out.getvalue() 1060 | 1061 | def csv(self, delimiter=','): 1062 | """Return data in CSV format""" 1063 | 1064 | data = self.dict() 1065 | out = StringIO() 1066 | writer = csv.writer(out, delimiter=delimiter, lineterminator='') 1067 | row = [data['server']['id'], data['server']['sponsor'], 1068 | data['server']['name'], data['timestamp'], 1069 | data['server']['d'], data['ping'], data['download'], 1070 | data['upload'], self._share or '', self.client['ip']] 1071 | writer.writerow([to_utf8(v) for v in row]) 1072 | return out.getvalue() 1073 | 1074 | def json(self, pretty=False): 1075 | """Return data in JSON format""" 1076 | 1077 | kwargs = {} 1078 | if pretty: 1079 | kwargs.update({ 1080 | 'indent': 4, 1081 | 'sort_keys': True 1082 | }) 1083 | return json.dumps(self.dict(), **kwargs) 1084 | 1085 | 1086 | class Speedtest(object): 1087 | """Class for performing standard speedtest.net testing operations""" 1088 | 1089 | def __init__(self, config=None, source_address=None, timeout=10, 1090 | secure=False, shutdown_event=None): 1091 | self.config = {} 1092 | 1093 | self._source_address = source_address 1094 | self._timeout = timeout 1095 | self._opener = build_opener(source_address, timeout) 1096 | 1097 | self._secure = secure 1098 | 1099 | if shutdown_event: 1100 | self._shutdown_event = shutdown_event 1101 | else: 1102 | self._shutdown_event = FakeShutdownEvent() 1103 | 1104 | self.get_config() 1105 | if config is not None: 1106 | self.config.update(config) 1107 | 1108 | self.servers = {} 1109 | self.closest = [] 1110 | self._best = {} 1111 | 1112 | self.results = SpeedtestResults( 1113 | client=self.config['client'], 1114 | opener=self._opener, 1115 | secure=secure, 1116 | ) 1117 | 1118 | @property 1119 | def best(self): 1120 | if not self._best: 1121 | self.get_best_server() 1122 | return self._best 1123 | 1124 | def get_config(self): 1125 | """Download the speedtest.net configuration and return only the data 1126 | we are interested in 1127 | """ 1128 | 1129 | headers = {} 1130 | if gzip: 1131 | headers['Accept-Encoding'] = 'gzip' 1132 | request = build_request('://www.speedtest.net/speedtest-config.php', 1133 | headers=headers, secure=self._secure) 1134 | uh, e = catch_request(request, opener=self._opener) 1135 | if e: 1136 | raise ConfigRetrievalError(e) 1137 | configxml_list = [] 1138 | 1139 | stream = get_response_stream(uh) 1140 | 1141 | while 1: 1142 | try: 1143 | configxml_list.append(stream.read(1024)) 1144 | except (OSError, EOFError): 1145 | raise ConfigRetrievalError(get_exception()) 1146 | if len(configxml_list[-1]) == 0: 1147 | break 1148 | stream.close() 1149 | uh.close() 1150 | 1151 | if int(uh.code) != 200: 1152 | return None 1153 | 1154 | configxml = ''.encode().join(configxml_list) 1155 | 1156 | printer('Config XML:\n%s' % configxml, debug=True) 1157 | 1158 | try: 1159 | try: 1160 | root = ET.fromstring(configxml) 1161 | except ET.ParseError: 1162 | e = get_exception() 1163 | raise SpeedtestConfigError( 1164 | 'Malformed speedtest.net configuration: %s' % e 1165 | ) 1166 | server_config = root.find('server-config').attrib 1167 | download = root.find('download').attrib 1168 | upload = root.find('upload').attrib 1169 | # times = root.find('times').attrib 1170 | client = root.find('client').attrib 1171 | 1172 | except AttributeError: 1173 | try: 1174 | root = DOM.parseString(configxml) 1175 | except ExpatError: 1176 | e = get_exception() 1177 | raise SpeedtestConfigError( 1178 | 'Malformed speedtest.net configuration: %s' % e 1179 | ) 1180 | server_config = get_attributes_by_tag_name(root, 'server-config') 1181 | download = get_attributes_by_tag_name(root, 'download') 1182 | upload = get_attributes_by_tag_name(root, 'upload') 1183 | # times = get_attributes_by_tag_name(root, 'times') 1184 | client = get_attributes_by_tag_name(root, 'client') 1185 | 1186 | ignore_servers = [ 1187 | int(i) for i in server_config['ignoreids'].split(',') if i 1188 | ] 1189 | 1190 | ratio = int(upload['ratio']) 1191 | upload_max = int(upload['maxchunkcount']) 1192 | up_sizes = [32768, 65536, 131072, 262144, 524288, 1048576, 7340032] 1193 | sizes = { 1194 | 'upload': up_sizes[ratio - 1:], 1195 | 'download': [350, 500, 750, 1000, 1500, 2000, 2500, 1196 | 3000, 3500, 4000] 1197 | } 1198 | 1199 | size_count = len(sizes['upload']) 1200 | 1201 | upload_count = int(math.ceil(upload_max / size_count)) 1202 | 1203 | counts = { 1204 | 'upload': upload_count, 1205 | 'download': int(download['threadsperurl']) 1206 | } 1207 | 1208 | threads = { 1209 | 'upload': int(upload['threads']), 1210 | 'download': int(server_config['threadcount']) * 2 1211 | } 1212 | 1213 | length = { 1214 | 'upload': int(upload['testlength']), 1215 | 'download': int(download['testlength']) 1216 | } 1217 | 1218 | self.config.update({ 1219 | 'client': client, 1220 | 'ignore_servers': ignore_servers, 1221 | 'sizes': sizes, 1222 | 'counts': counts, 1223 | 'threads': threads, 1224 | 'length': length, 1225 | 'upload_max': upload_count * size_count 1226 | }) 1227 | 1228 | try: 1229 | self.lat_lon = (float(client['lat']), float(client['lon'])) 1230 | except ValueError: 1231 | raise SpeedtestConfigError( 1232 | 'Unknown location: lat=%r lon=%r' % 1233 | (client.get('lat'), client.get('lon')) 1234 | ) 1235 | 1236 | printer('Config:\n%r' % self.config, debug=True) 1237 | 1238 | return self.config 1239 | 1240 | def get_servers(self, servers=None, exclude=None): 1241 | """Retrieve a the list of speedtest.net servers, optionally filtered 1242 | to servers matching those specified in the ``servers`` argument 1243 | """ 1244 | if servers is None: 1245 | servers = [] 1246 | 1247 | if exclude is None: 1248 | exclude = [] 1249 | 1250 | self.servers.clear() 1251 | 1252 | for server_list in (servers, exclude): 1253 | for i, s in enumerate(server_list): 1254 | try: 1255 | server_list[i] = int(s) 1256 | except ValueError: 1257 | raise InvalidServerIDType( 1258 | '%s is an invalid server type, must be int' % s 1259 | ) 1260 | 1261 | urls = [ 1262 | '://www.speedtest.net/speedtest-servers-static.php', 1263 | 'http://c.speedtest.net/speedtest-servers-static.php', 1264 | '://www.speedtest.net/speedtest-servers.php', 1265 | 'http://c.speedtest.net/speedtest-servers.php', 1266 | ] 1267 | 1268 | headers = {} 1269 | if gzip: 1270 | headers['Accept-Encoding'] = 'gzip' 1271 | 1272 | errors = [] 1273 | for url in urls: 1274 | try: 1275 | request = build_request( 1276 | '%s?threads=%s' % (url, 1277 | self.config['threads']['download']), 1278 | headers=headers, 1279 | secure=self._secure 1280 | ) 1281 | uh, e = catch_request(request, opener=self._opener) 1282 | if e: 1283 | errors.append('%s' % e) 1284 | raise ServersRetrievalError() 1285 | 1286 | stream = get_response_stream(uh) 1287 | 1288 | serversxml_list = [] 1289 | while 1: 1290 | try: 1291 | serversxml_list.append(stream.read(1024)) 1292 | except (OSError, EOFError): 1293 | raise ServersRetrievalError(get_exception()) 1294 | if len(serversxml_list[-1]) == 0: 1295 | break 1296 | 1297 | stream.close() 1298 | uh.close() 1299 | 1300 | if int(uh.code) != 200: 1301 | raise ServersRetrievalError() 1302 | 1303 | serversxml = ''.encode().join(serversxml_list) 1304 | 1305 | printer('Servers XML:\n%s' % serversxml, debug=True) 1306 | 1307 | try: 1308 | try: 1309 | try: 1310 | root = ET.fromstring(serversxml) 1311 | except ET.ParseError: 1312 | e = get_exception() 1313 | raise SpeedtestServersError( 1314 | 'Malformed speedtest.net server list: %s' % e 1315 | ) 1316 | elements = etree_iter(root, 'server') 1317 | except AttributeError: 1318 | try: 1319 | root = DOM.parseString(serversxml) 1320 | except ExpatError: 1321 | e = get_exception() 1322 | raise SpeedtestServersError( 1323 | 'Malformed speedtest.net server list: %s' % e 1324 | ) 1325 | elements = root.getElementsByTagName('server') 1326 | except (SyntaxError, xml.parsers.expat.ExpatError): 1327 | raise ServersRetrievalError() 1328 | 1329 | for server in elements: 1330 | try: 1331 | attrib = server.attrib 1332 | except AttributeError: 1333 | attrib = dict(list(server.attributes.items())) 1334 | 1335 | if servers and int(attrib.get('id')) not in servers: 1336 | continue 1337 | 1338 | if (int(attrib.get('id')) in self.config['ignore_servers'] 1339 | or int(attrib.get('id')) in exclude): 1340 | continue 1341 | 1342 | try: 1343 | d = distance(self.lat_lon, 1344 | (float(attrib.get('lat')), 1345 | float(attrib.get('lon')))) 1346 | except Exception: 1347 | continue 1348 | 1349 | attrib['d'] = d 1350 | 1351 | try: 1352 | self.servers[d].append(attrib) 1353 | except KeyError: 1354 | self.servers[d] = [attrib] 1355 | 1356 | break 1357 | 1358 | except ServersRetrievalError: 1359 | continue 1360 | 1361 | if (servers or exclude) and not self.servers: 1362 | raise NoMatchedServers() 1363 | 1364 | return self.servers 1365 | 1366 | def set_mini_server(self, server): 1367 | """Instead of querying for a list of servers, set a link to a 1368 | speedtest mini server 1369 | """ 1370 | 1371 | urlparts = urlparse(server) 1372 | 1373 | name, ext = os.path.splitext(urlparts[2]) 1374 | if ext: 1375 | url = os.path.dirname(server) 1376 | else: 1377 | url = server 1378 | 1379 | request = build_request(url) 1380 | uh, e = catch_request(request, opener=self._opener) 1381 | if e: 1382 | raise SpeedtestMiniConnectFailure('Failed to connect to %s' % 1383 | server) 1384 | else: 1385 | text = uh.read() 1386 | uh.close() 1387 | 1388 | extension = re.findall('upload_?[Ee]xtension: "([^"]+)"', 1389 | text.decode()) 1390 | if not extension: 1391 | for ext in ['php', 'asp', 'aspx', 'jsp']: 1392 | try: 1393 | f = self._opener.open( 1394 | '%s/speedtest/upload.%s' % (url, ext) 1395 | ) 1396 | except Exception: 1397 | pass 1398 | else: 1399 | data = f.read().strip().decode() 1400 | if (f.code == 200 and 1401 | len(data.splitlines()) == 1 and 1402 | re.match('size=[0-9]', data)): 1403 | extension = [ext] 1404 | break 1405 | if not urlparts or not extension: 1406 | raise InvalidSpeedtestMiniServer('Invalid Speedtest Mini Server: ' 1407 | '%s' % server) 1408 | 1409 | self.servers = [{ 1410 | 'sponsor': 'Speedtest Mini', 1411 | 'name': urlparts[1], 1412 | 'd': 0, 1413 | 'url': '%s/speedtest/upload.%s' % (url.rstrip('/'), extension[0]), 1414 | 'latency': 0, 1415 | 'id': 0 1416 | }] 1417 | 1418 | return self.servers 1419 | 1420 | def get_closest_servers(self, limit=5): 1421 | """Limit servers to the closest speedtest.net servers based on 1422 | geographic distance 1423 | """ 1424 | 1425 | if not self.servers: 1426 | self.get_servers() 1427 | 1428 | for d in sorted(self.servers.keys()): 1429 | for s in self.servers[d]: 1430 | self.closest.append(s) 1431 | if len(self.closest) == limit: 1432 | break 1433 | else: 1434 | continue 1435 | break 1436 | 1437 | printer('Closest Servers:\n%r' % self.closest, debug=True) 1438 | return self.closest 1439 | 1440 | def get_best_server(self, servers=None): 1441 | """Perform a speedtest.net "ping" to determine which speedtest.net 1442 | server has the lowest latency 1443 | """ 1444 | 1445 | if not servers: 1446 | if not self.closest: 1447 | servers = self.get_closest_servers() 1448 | servers = self.closest 1449 | 1450 | if self._source_address: 1451 | source_address_tuple = (self._source_address, 0) 1452 | else: 1453 | source_address_tuple = None 1454 | 1455 | user_agent = build_user_agent() 1456 | 1457 | results = {} 1458 | for server in servers: 1459 | cum = [] 1460 | url = os.path.dirname(server['url']) 1461 | stamp = int(timeit.time.time() * 1000) 1462 | latency_url = '%s/latency.txt?x=%s' % (url, stamp) 1463 | for i in range(0, 3): 1464 | this_latency_url = '%s.%s' % (latency_url, i) 1465 | printer('%s %s' % ('GET', this_latency_url), 1466 | debug=True) 1467 | urlparts = urlparse(latency_url) 1468 | try: 1469 | if urlparts[0] == 'https': 1470 | h = SpeedtestHTTPSConnection( 1471 | urlparts[1], 1472 | source_address=source_address_tuple 1473 | ) 1474 | else: 1475 | h = SpeedtestHTTPConnection( 1476 | urlparts[1], 1477 | source_address=source_address_tuple 1478 | ) 1479 | headers = {'User-Agent': user_agent} 1480 | path = '%s?%s' % (urlparts[2], urlparts[4]) 1481 | start = timeit.default_timer() 1482 | h.request("GET", path, headers=headers) 1483 | r = h.getresponse() 1484 | total = (timeit.default_timer() - start) 1485 | except HTTP_ERRORS: 1486 | e = get_exception() 1487 | printer('ERROR: %r' % e, debug=True) 1488 | cum.append(3600) 1489 | continue 1490 | 1491 | text = r.read(9) 1492 | if int(r.status) == 200 and text == 'test=test'.encode(): 1493 | cum.append(total) 1494 | else: 1495 | cum.append(3600) 1496 | h.close() 1497 | 1498 | avg = round((sum(cum) / 6) * 1000.0, 3) 1499 | results[avg] = server 1500 | 1501 | try: 1502 | fastest = sorted(results.keys())[0] 1503 | except IndexError: 1504 | raise SpeedtestBestServerFailure('Unable to connect to servers to ' 1505 | 'test latency.') 1506 | best = results[fastest] 1507 | best['latency'] = fastest 1508 | 1509 | self.results.ping = fastest 1510 | self.results.server = best 1511 | 1512 | self._best.update(best) 1513 | printer('Best Server:\n%r' % best, debug=True) 1514 | return best 1515 | 1516 | def download(self, callback=do_nothing, threads=None): 1517 | """Test download speed against speedtest.net 1518 | 1519 | A ``threads`` value of ``None`` will fall back to those dictated 1520 | by the speedtest.net configuration 1521 | """ 1522 | 1523 | urls = [] 1524 | for size in self.config['sizes']['download']: 1525 | for _ in range(0, self.config['counts']['download']): 1526 | urls.append('%s/random%sx%s.jpg' % 1527 | (os.path.dirname(self.best['url']), size, size)) 1528 | 1529 | request_count = len(urls) 1530 | requests = [] 1531 | for i, url in enumerate(urls): 1532 | requests.append( 1533 | build_request(url, bump=i, secure=self._secure) 1534 | ) 1535 | 1536 | max_threads = threads or self.config['threads']['download'] 1537 | in_flight = {'threads': 0} 1538 | 1539 | def producer(q, requests, request_count): 1540 | for i, request in enumerate(requests): 1541 | thread = HTTPDownloader( 1542 | i, 1543 | request, 1544 | start, 1545 | self.config['length']['download'], 1546 | opener=self._opener, 1547 | shutdown_event=self._shutdown_event 1548 | ) 1549 | while in_flight['threads'] >= max_threads: 1550 | timeit.time.sleep(0.001) 1551 | thread.start() 1552 | q.put(thread, True) 1553 | in_flight['threads'] += 1 1554 | callback(i, request_count, start=True) 1555 | 1556 | finished = [] 1557 | 1558 | def consumer(q, request_count): 1559 | _is_alive = thread_is_alive 1560 | while len(finished) < request_count: 1561 | thread = q.get(True) 1562 | while _is_alive(thread): 1563 | thread.join(timeout=0.001) 1564 | in_flight['threads'] -= 1 1565 | finished.append(sum(thread.result)) 1566 | callback(thread.i, request_count, end=True) 1567 | 1568 | q = Queue(max_threads) 1569 | prod_thread = threading.Thread(target=producer, 1570 | args=(q, requests, request_count)) 1571 | cons_thread = threading.Thread(target=consumer, 1572 | args=(q, request_count)) 1573 | start = timeit.default_timer() 1574 | prod_thread.start() 1575 | cons_thread.start() 1576 | _is_alive = thread_is_alive 1577 | while _is_alive(prod_thread): 1578 | prod_thread.join(timeout=0.001) 1579 | while _is_alive(cons_thread): 1580 | cons_thread.join(timeout=0.001) 1581 | 1582 | stop = timeit.default_timer() 1583 | self.results.bytes_received = sum(finished) 1584 | self.results.download = ( 1585 | (self.results.bytes_received / (stop - start)) * 8.0 1586 | ) 1587 | if self.results.download > 100000: 1588 | self.config['threads']['upload'] = 8 1589 | return self.results.download 1590 | 1591 | def upload(self, callback=do_nothing, pre_allocate=True, threads=None): 1592 | """Test upload speed against speedtest.net 1593 | 1594 | A ``threads`` value of ``None`` will fall back to those dictated 1595 | by the speedtest.net configuration 1596 | """ 1597 | 1598 | sizes = [] 1599 | 1600 | for size in self.config['sizes']['upload']: 1601 | for _ in range(0, self.config['counts']['upload']): 1602 | sizes.append(size) 1603 | 1604 | # request_count = len(sizes) 1605 | request_count = self.config['upload_max'] 1606 | 1607 | requests = [] 1608 | for i, size in enumerate(sizes): 1609 | # We set ``0`` for ``start`` and handle setting the actual 1610 | # ``start`` in ``HTTPUploader`` to get better measurements 1611 | data = HTTPUploaderData( 1612 | size, 1613 | 0, 1614 | self.config['length']['upload'], 1615 | shutdown_event=self._shutdown_event 1616 | ) 1617 | if pre_allocate: 1618 | data.pre_allocate() 1619 | 1620 | headers = {'Content-length': size} 1621 | requests.append( 1622 | ( 1623 | build_request(self.best['url'], data, secure=self._secure, 1624 | headers=headers), 1625 | size 1626 | ) 1627 | ) 1628 | 1629 | max_threads = threads or self.config['threads']['upload'] 1630 | in_flight = {'threads': 0} 1631 | 1632 | def producer(q, requests, request_count): 1633 | for i, request in enumerate(requests[:request_count]): 1634 | thread = HTTPUploader( 1635 | i, 1636 | request[0], 1637 | start, 1638 | request[1], 1639 | self.config['length']['upload'], 1640 | opener=self._opener, 1641 | shutdown_event=self._shutdown_event 1642 | ) 1643 | while in_flight['threads'] >= max_threads: 1644 | timeit.time.sleep(0.001) 1645 | thread.start() 1646 | q.put(thread, True) 1647 | in_flight['threads'] += 1 1648 | callback(i, request_count, start=True) 1649 | 1650 | finished = [] 1651 | 1652 | def consumer(q, request_count): 1653 | _is_alive = thread_is_alive 1654 | while len(finished) < request_count: 1655 | thread = q.get(True) 1656 | while _is_alive(thread): 1657 | thread.join(timeout=0.001) 1658 | in_flight['threads'] -= 1 1659 | finished.append(thread.result) 1660 | callback(thread.i, request_count, end=True) 1661 | 1662 | q = Queue(threads or self.config['threads']['upload']) 1663 | prod_thread = threading.Thread(target=producer, 1664 | args=(q, requests, request_count)) 1665 | cons_thread = threading.Thread(target=consumer, 1666 | args=(q, request_count)) 1667 | start = timeit.default_timer() 1668 | prod_thread.start() 1669 | cons_thread.start() 1670 | _is_alive = thread_is_alive 1671 | while _is_alive(prod_thread): 1672 | prod_thread.join(timeout=0.1) 1673 | while _is_alive(cons_thread): 1674 | cons_thread.join(timeout=0.1) 1675 | 1676 | stop = timeit.default_timer() 1677 | self.results.bytes_sent = sum(finished) 1678 | self.results.upload = ( 1679 | (self.results.bytes_sent / (stop - start)) * 8.0 1680 | ) 1681 | return self.results.upload 1682 | 1683 | 1684 | def ctrl_c(shutdown_event): 1685 | """Catch Ctrl-C key sequence and set a SHUTDOWN_EVENT for our threaded 1686 | operations 1687 | """ 1688 | def inner(signum, frame): 1689 | shutdown_event.set() 1690 | printer('\nCancelling...', error=True) 1691 | sys.exit(0) 1692 | return inner 1693 | 1694 | 1695 | def version(): 1696 | """Print the version""" 1697 | 1698 | printer('speedtest-cli %s' % __version__) 1699 | printer('Python %s' % sys.version.replace('\n', '')) 1700 | sys.exit(0) 1701 | 1702 | 1703 | def csv_header(delimiter=','): 1704 | """Print the CSV Headers""" 1705 | 1706 | printer(SpeedtestResults.csv_header(delimiter=delimiter)) 1707 | sys.exit(0) 1708 | 1709 | 1710 | def parse_args(): 1711 | """Function to handle building and parsing of command line arguments""" 1712 | description = ( 1713 | 'Command line interface for testing internet bandwidth using ' 1714 | 'speedtest.net.\n' 1715 | '------------------------------------------------' 1716 | '--------------\n' 1717 | 'https://github.com/sivel/speedtest-cli') 1718 | 1719 | parser = ArgParser(description=description) 1720 | # Give optparse.OptionParser an `add_argument` method for 1721 | # compatibility with argparse.ArgumentParser 1722 | try: 1723 | parser.add_argument = parser.add_option 1724 | except AttributeError: 1725 | pass 1726 | parser.add_argument('--no-download', dest='download', default=True, 1727 | action='store_const', const=False, 1728 | help='Do not perform download test') 1729 | parser.add_argument('--no-upload', dest='upload', default=True, 1730 | action='store_const', const=False, 1731 | help='Do not perform upload test') 1732 | parser.add_argument('--single', default=False, action='store_true', 1733 | help='Only use a single connection instead of ' 1734 | 'multiple. This simulates a typical file ' 1735 | 'transfer.') 1736 | parser.add_argument('--bytes', dest='units', action='store_const', 1737 | const=('byte', 8), default=('bit', 1), 1738 | help='Display values in bytes instead of bits. Does ' 1739 | 'not affect the image generated by --share, nor ' 1740 | 'output from --json or --csv') 1741 | parser.add_argument('--share', action='store_true', 1742 | help='Generate and provide a URL to the speedtest.net ' 1743 | 'share results image, not displayed with --csv') 1744 | parser.add_argument('--simple', action='store_true', default=False, 1745 | help='Suppress verbose output, only show basic ' 1746 | 'information') 1747 | parser.add_argument('--csv', action='store_true', default=False, 1748 | help='Suppress verbose output, only show basic ' 1749 | 'information in CSV format. Speeds listed in ' 1750 | 'bit/s and not affected by --bytes') 1751 | parser.add_argument('--csv-delimiter', default=',', type=PARSER_TYPE_STR, 1752 | help='Single character delimiter to use in CSV ' 1753 | 'output. Default ","') 1754 | parser.add_argument('--csv-header', action='store_true', default=False, 1755 | help='Print CSV headers') 1756 | parser.add_argument('--json', action='store_true', default=False, 1757 | help='Suppress verbose output, only show basic ' 1758 | 'information in JSON format. Speeds listed in ' 1759 | 'bit/s and not affected by --bytes') 1760 | parser.add_argument('--list', action='store_true', 1761 | help='Display a list of speedtest.net servers ' 1762 | 'sorted by distance') 1763 | parser.add_argument('--server', type=PARSER_TYPE_INT, action='append', 1764 | help='Specify a server ID to test against. Can be ' 1765 | 'supplied multiple times') 1766 | parser.add_argument('--exclude', type=PARSER_TYPE_INT, action='append', 1767 | help='Exclude a server from selection. Can be ' 1768 | 'supplied multiple times') 1769 | parser.add_argument('--mini', help='URL of the Speedtest Mini server') 1770 | parser.add_argument('--source', help='Source IP address to bind to') 1771 | parser.add_argument('--timeout', default=10, type=PARSER_TYPE_FLOAT, 1772 | help='HTTP timeout in seconds. Default 10') 1773 | parser.add_argument('--secure', action='store_true', 1774 | help='Use HTTPS instead of HTTP when communicating ' 1775 | 'with speedtest.net operated servers') 1776 | parser.add_argument('--no-pre-allocate', dest='pre_allocate', 1777 | action='store_const', default=True, const=False, 1778 | help='Do not pre allocate upload data. Pre allocation ' 1779 | 'is enabled by default to improve upload ' 1780 | 'performance. To support systems with ' 1781 | 'insufficient memory, use this option to avoid a ' 1782 | 'MemoryError') 1783 | parser.add_argument('--version', action='store_true', 1784 | help='Show the version number and exit') 1785 | parser.add_argument('--debug', action='store_true', 1786 | help=ARG_SUPPRESS, default=ARG_SUPPRESS) 1787 | 1788 | options = parser.parse_args() 1789 | if isinstance(options, tuple): 1790 | args = options[0] 1791 | else: 1792 | args = options 1793 | return args 1794 | 1795 | 1796 | def validate_optional_args(args): 1797 | """Check if an argument was provided that depends on a module that may 1798 | not be part of the Python standard library. 1799 | 1800 | If such an argument is supplied, and the module does not exist, exit 1801 | with an error stating which module is missing. 1802 | """ 1803 | optional_args = { 1804 | 'json': ('json/simplejson python module', json), 1805 | 'secure': ('SSL support', HTTPSConnection), 1806 | } 1807 | 1808 | for arg, info in optional_args.items(): 1809 | if getattr(args, arg, False) and info[1] is None: 1810 | raise SystemExit('%s is not installed. --%s is ' 1811 | 'unavailable' % (info[0], arg)) 1812 | 1813 | 1814 | def printer(string, quiet=False, debug=False, error=False, **kwargs): 1815 | """Helper function print a string with various features""" 1816 | 1817 | if debug and not DEBUG: 1818 | return 1819 | 1820 | if debug: 1821 | if sys.stdout.isatty(): 1822 | out = '\033[1;30mDEBUG: %s\033[0m' % string 1823 | else: 1824 | out = 'DEBUG: %s' % string 1825 | else: 1826 | out = string 1827 | 1828 | if error: 1829 | kwargs['file'] = sys.stderr 1830 | 1831 | if not quiet: 1832 | print_(out, **kwargs) 1833 | 1834 | 1835 | def shell(): 1836 | """Run the full speedtest.net test""" 1837 | 1838 | global DEBUG 1839 | shutdown_event = threading.Event() 1840 | 1841 | signal.signal(signal.SIGINT, ctrl_c(shutdown_event)) 1842 | 1843 | args = parse_args() 1844 | 1845 | # Print the version and exit 1846 | if args.version: 1847 | version() 1848 | 1849 | if not args.download and not args.upload: 1850 | raise SpeedtestCLIError('Cannot supply both --no-download and ' 1851 | '--no-upload') 1852 | 1853 | if len(args.csv_delimiter) != 1: 1854 | raise SpeedtestCLIError('--csv-delimiter must be a single character') 1855 | 1856 | if args.csv_header: 1857 | csv_header(args.csv_delimiter) 1858 | 1859 | validate_optional_args(args) 1860 | 1861 | debug = getattr(args, 'debug', False) 1862 | if debug == 'SUPPRESSHELP': 1863 | debug = False 1864 | if debug: 1865 | DEBUG = True 1866 | 1867 | if args.simple or args.csv or args.json: 1868 | quiet = True 1869 | else: 1870 | quiet = False 1871 | 1872 | if args.csv or args.json: 1873 | machine_format = True 1874 | else: 1875 | machine_format = False 1876 | 1877 | # Don't set a callback if we are running quietly 1878 | if quiet or debug: 1879 | callback = do_nothing 1880 | else: 1881 | callback = print_dots(shutdown_event) 1882 | 1883 | printer('', quiet) 1884 | try: 1885 | speedtest = Speedtest( 1886 | source_address=args.source, 1887 | timeout=args.timeout, 1888 | secure=args.secure 1889 | ) 1890 | except (ConfigRetrievalError,) + HTTP_ERRORS: 1891 | printer('Cannot retrieve speedtest configuration', error=True) 1892 | raise SpeedtestCLIError(get_exception()) 1893 | 1894 | if args.list: 1895 | try: 1896 | speedtest.get_servers() 1897 | except (ServersRetrievalError,) + HTTP_ERRORS: 1898 | printer('Cannot retrieve speedtest server list', error=True) 1899 | raise SpeedtestCLIError(get_exception()) 1900 | 1901 | for _, servers in sorted(speedtest.servers.items()): 1902 | for server in servers: 1903 | line = ('%(id)5s) %(sponsor)s (%(name)s, %(country)s) ' 1904 | '[%(d)0.2f km]' % server) 1905 | try: 1906 | printer(line) 1907 | except IOError: 1908 | e = get_exception() 1909 | if e.errno != errno.EPIPE: 1910 | raise 1911 | sys.exit(0) 1912 | 1913 | printer('*🌁 ᴛᴇsᴛɪɴɢ ғʀᴏᴍ %(isp)s...*\n' % speedtest.config['client'], 1914 | quiet) 1915 | 1916 | if not args.mini: 1917 | printer('📑 ʀᴇᴛʀɪᴇᴠɪɴɢ speedtest.net sᴇʀᴠᴇʀ ʟɪsᴛ...', quiet) 1918 | try: 1919 | speedtest.get_servers(servers=args.server, exclude=args.exclude) 1920 | except NoMatchedServers: 1921 | raise SpeedtestCLIError( 1922 | 'No matched servers: %s' % 1923 | ', '.join('%s' % s for s in args.server) 1924 | ) 1925 | except (ServersRetrievalError,) + HTTP_ERRORS: 1926 | printer('Cannot retrieve speedtest server list', error=True) 1927 | raise SpeedtestCLIError(get_exception()) 1928 | except InvalidServerIDType: 1929 | raise SpeedtestCLIError( 1930 | '%s is an invalid server type, must ' 1931 | 'be an int' % ', '.join('%s' % s for s in args.server) 1932 | ) 1933 | 1934 | if args.server and len(args.server) == 1: 1935 | printer('📚 Retrieving information for the selected server...', quiet) 1936 | else: 1937 | printer('🔍 sᴇʟᴇᴄᴛɪɴɢ ʙᴇsᴛ sᴇʀᴠᴇʀ ʙᴀsᴇᴅ ᴏɴ ᴘɪɴɢ...', quiet) 1938 | speedtest.get_best_server() 1939 | elif args.mini: 1940 | speedtest.get_best_server(speedtest.set_mini_server(args.mini)) 1941 | 1942 | results = speedtest.results 1943 | 1944 | printer('\n..................................................\n🏠 *ʜᴏsᴛᴇᴅ ʙʏ :* %(sponsor)s\n🌍 *ʟᴏᴄᴀᴛɪᴏɴ :* %(name)s [%(d)0.2f km] ' 1945 | '\n⚡ *ᴘɪɴɢ :* %(latency)s ms' % results.server, quiet) 1946 | 1947 | if args.download: 1948 | printer('', quiet, 1949 | end=('', '\n')[bool(debug)]) 1950 | speedtest.download( 1951 | callback=callback, 1952 | threads=(None, 1)[args.single] 1953 | ) 1954 | printer('*📥 ᴅᴏᴡɴʟᴏᴀᴅ:* %0.2f M%s/s' % 1955 | ((results.download / 1000.0 / 1000.0) / args.units[1], 1956 | args.units[0]), 1957 | quiet) 1958 | else: 1959 | printer('Skipping download test', quiet) 1960 | 1961 | if args.upload: 1962 | speedtest.upload() 1963 | printer('*📤 ᴜᴘʟᴏᴀᴅ:* %0.2f M%s/s' % 1964 | ((results.upload / 1000.0 / 1000.0) / args.units[1], 1965 | args.units[0]), 1966 | quiet) 1967 | printer("\n..................................................\n↬ ᴘᴏᴡᴇʀᴇᴅ ʙʏ *sᴘᴇᴇᴅᴛᴇsᴛ Ookla*") 1968 | else: 1969 | printer('Skipping upload test', quiet) 1970 | 1971 | printer('Results:\n%r' % results.dict(), debug=True) 1972 | 1973 | if not args.simple and args.share: 1974 | results.share() 1975 | 1976 | if args.simple: 1977 | printer('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' % 1978 | (results.ping, 1979 | (results.download / 1000.0 / 1000.0) / args.units[1], 1980 | args.units[0], 1981 | (results.upload / 1000.0 / 1000.0) / args.units[1], 1982 | args.units[0])) 1983 | elif args.csv: 1984 | printer(results.csv(delimiter=args.csv_delimiter)) 1985 | elif args.json: 1986 | printer(results.json()) 1987 | 1988 | if args.share and not machine_format: 1989 | printer('Share results: %s' % results.share()) 1990 | 1991 | 1992 | def main(): 1993 | try: 1994 | shell() 1995 | except KeyboardInterrupt: 1996 | printer('\nCancelling...', error=True) 1997 | except (SpeedtestException, SystemExit): 1998 | e = get_exception() 1999 | # Ignore a successful exit, or argparse exit 2000 | if getattr(e, 'code', 1) not in (0, 2): 2001 | msg = '%s' % e 2002 | if not msg: 2003 | msg = '%r' % e 2004 | raise SystemExit('ERROR: %s' % msg) 2005 | 2006 | 2007 | if __name__ == '__main__': 2008 | main() 2009 | -------------------------------------------------------------------------------- /src/SYCHYY NO FES NO NEM: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/database.js: -------------------------------------------------------------------------------- 1 | require('../settings'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const chalk = require('chalk'); 5 | const mongoose = require('mongoose'); 6 | let DataBase; 7 | 8 | if (/mongo/.test(global.tempatDB)) { 9 | DataBase = class mongoDB { 10 | constructor(url = global.tempatDB, options = { useNewUrlParser: true, useUnifiedTopology: true }) { 11 | this.url = url 12 | this.data = {} 13 | this._model = {} 14 | this.options = options 15 | } 16 | 17 | read = async () => { 18 | mongoose.connect(this.url, { ...this.options }) 19 | this.connection = mongoose.connection 20 | try { 21 | const schema = new mongoose.Schema({ 22 | data: { 23 | type: Object, 24 | required: true, 25 | default: {}, 26 | } 27 | }) 28 | this._model = mongoose.model('data', schema) 29 | } catch { 30 | this._model = mongoose.model('data') 31 | } 32 | this.data = await this._model.findOne({}) 33 | if (!this.data) { 34 | new this._model({ data: {} }).save() 35 | this.data = await this._model.findOne({}) 36 | } else return this?.data?.data || this?.data 37 | } 38 | 39 | write = async (data) => { 40 | if (this.data && !this.data.data) return (new this._model({ data })).save() 41 | this._model.findById(this.data._id, (err, docs) => { 42 | if (!err) { 43 | if (!docs.data) docs.data = {} 44 | docs.data = data 45 | return docs.save() 46 | } 47 | }) 48 | } 49 | } 50 | } else if (/json/.test(global.tempatDB)) { 51 | DataBase = class dataBase { 52 | data = {} 53 | file = path.join(process.cwd(), 'database', global.tempatDB); 54 | 55 | read = async () => { 56 | let data; 57 | if (fs.existsSync(this.file)) { 58 | data = JSON.parse(fs.readFileSync(this.file)) 59 | } else { 60 | fs.writeFileSync(this.file, JSON.stringify(this.data, null, 2)) 61 | data = this.data 62 | } 63 | return data 64 | } 65 | 66 | write = async (data) => { 67 | this.data = !!data ? data : global.db 68 | let dirname = path.dirname(this.file) 69 | if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true }) 70 | fs.writeFileSync(this.file, JSON.stringify(this.data, null, 2)) 71 | return this.file 72 | } 73 | } 74 | } 75 | 76 | module.exports = DataBase 77 | 78 | 79 | let file = require.resolve(__filename) 80 | fs.watchFile(file, () => { 81 | fs.unwatchFile(file) 82 | console.log(chalk.redBright(`Update ${__filename}`)) 83 | delete require.cache[file] 84 | require(file) 85 | }); -------------------------------------------------------------------------------- /src/media/SYCHY-BOTz: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/media/fake.pdf: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/media/gmbr: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/media/stc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/media/stc.webp -------------------------------------------------------------------------------- /src/media/sych.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/media/sych.png -------------------------------------------------------------------------------- /src/media/sychy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/media/sychy.png -------------------------------------------------------------------------------- /src/message.js: -------------------------------------------------------------------------------- 1 | require('../settings'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const https = require('https'); 5 | const axios = require('axios'); 6 | const chalk = require('chalk'); 7 | const FileType = require('file-type'); 8 | const PhoneNumber = require('awesome-phonenumber'); 9 | 10 | const prem = require('./premium'); 11 | const { imageToWebp, videoToWebp, writeExif } = require('../lib/exif'); 12 | const premium = JSON.parse(fs.readFileSync('./database/premium.json')); 13 | const { isUrl, getGroupAdmins, generateMessageTag, getBuffer, getSizeMedia, fetchJson, sleep, getTypeUrlMedia } = require('../lib/function'); 14 | const { jidNormalizedUser, proto, getBinaryNodeChildren, getBinaryNodeChild, generateWAMessageContent, generateForwardMessageContent, prepareWAMessageMedia, delay, areJidsSameUser, extractMessageContent, generateMessageID, downloadContentFromMessage, generateWAMessageFromContent, jidDecode, generateWAMessage, toBuffer, getContentType, getDevice } = require('@whiskeysockets/baileys'); 15 | 16 | /* 17 | * Create By sych 18 | * Follow https://github.com/sychdev 19 | * Whatsapp : https://whatsapp.com/channel/0029VaWOkNm7DAWtkvkJBK43 20 | */ 21 | 22 | async function GroupUpdate(sych, update, store) { 23 | try { 24 | for (let n of update) { 25 | if (store.groupMetadata[n.id]) { 26 | store.groupMetadata[n.id] = { 27 | ...(store.groupMetadata[n.id] || {}), 28 | ...(n || {}) 29 | } 30 | } 31 | } 32 | } catch (e) { 33 | throw e; 34 | } 35 | } 36 | 37 | async function GroupParticipantsUpdate(sych, { id, participants, author, action }, store) { 38 | try { 39 | function updateAdminStatus(participants, metadataParticipants, status) { 40 | for (const participant of metadataParticipants) { 41 | let id = jidNormalizedUser(participant.id); 42 | if (participants.includes(id)) { 43 | participant.admin = status; 44 | } 45 | } 46 | } 47 | if (global.db.groups && global.db.groups[id] && store.groupMetadata && store.groupMetadata[id]) { 48 | const metadata = store.groupMetadata[id]; 49 | for (let n of participants) { 50 | let profile; 51 | try { 52 | profile = await sych.profilePictureUrl(n, 'image'); 53 | } catch { 54 | profile = 'https://telegra.ph/file/95670d63378f7f4210f03.png'; 55 | } 56 | let messageText; 57 | if (action === 'add') { 58 | messageText = `Welcome to ${metadata.subject}\n@${n.split('@')[0]}`; 59 | metadata.participants.push({ id: jidNormalizedUser(n), admin: null }); 60 | } else if (action === 'remove') { 61 | messageText = `@${n.split('@')[0]}\nLeaving From ${metadata.subject}`; 62 | metadata.participants = metadata.participants.filter(p => !participants.includes(jidNormalizedUser(p.id))); 63 | } else if (action === 'promote') { 64 | messageText = `@${n.split('@')[0]}\nPromote From ${metadata.subject}\nBy @${author.split('@')[0]}`; 65 | updateAdminStatus(participants, metadata.participants, 'admin'); 66 | } else if (action === 'demote') { 67 | messageText = `@${n.split('@')[0]}\nDemote From ${metadata.subject}\nBy @${author.split('@')[0]}`; 68 | updateAdminStatus(participants, metadata.participants, null); 69 | } 70 | if (messageText && global.db.groups[id].welcome) { 71 | await sych.sendMessage(id, { 72 | text: messageText, 73 | contextInfo: { 74 | mentionedJid: [n, author], 75 | externalAdReply: { 76 | title: action == 'add' ? 'Welcome' : action == 'remove' ? 'Leaving' : action.charAt(0).toUpperCase() + action.slice(1), 77 | mediaType: 1, 78 | previewType: 0, 79 | thumbnailUrl: profile, 80 | renderLargerThumbnail: true, 81 | sourceUrl: global.my.gh 82 | } 83 | } 84 | }); 85 | } 86 | } 87 | } 88 | } catch (e) { 89 | throw e; 90 | } 91 | } 92 | 93 | async function LoadDataBase(sych, m) { 94 | try { 95 | const botNumber = await sych.decodeJid(sych.user.id); 96 | const isNumber = x => typeof x === 'number' && !isNaN(x) 97 | const isBoolean = x => typeof x === 'boolean' && Boolean(x) 98 | let user = global.db.users[m.sender] 99 | let setBot = global.db.set[botNumber] 100 | let limitUser = user ? (user.vip ? global.limit.vip : prem.checkPremiumUser(m.sender, premium) ? global.limit.premium : global.limit.free) : prem.checkPremiumUser(m.sender, premium) ? global.limit.premium : global.limit.free 101 | let uangUser = user ? (user.vip ? global.uang.vip : prem.checkPremiumUser(m.sender, premium) ? global.uang.premium : global.uang.free) : prem.checkPremiumUser(m.sender, premium) ? global.uang.premium : global.uang.free 102 | if (typeof setBot !== 'object') global.db.set[botNumber] = {} 103 | if (setBot) { 104 | if (!('lang' in setBot)) setBot.lang = 'id' 105 | if (!('limit' in setBot)) setBot.limit = 0 106 | if (!('uang' in setBot)) setBot.uang = 0 107 | if (!('status' in setBot)) setBot.status = 0 108 | if (!('join' in setBot)) setBot.join = false 109 | if (!('public' in setBot)) setBot.public = true 110 | if (!('anticall' in setBot)) setBot.anticall = true 111 | if (!('readsw' in setBot)) setBot.readsw = false 112 | if (!('autobio' in setBot)) setBot.autobio = false 113 | if (!('autoread' in setBot)) setBot.autoread = true 114 | if (!('autotyping' in setBot)) setBot.autotyping = true 115 | if (!('template' in setBot)) setBot.template = 'textMessage' 116 | } else { 117 | global.db.set[botNumber] = { 118 | lang: 'id', 119 | limit: 0, 120 | uang: 0, 121 | status: 0, 122 | join: false, 123 | public: true, 124 | anticall: true, 125 | readsw: false, 126 | autobio: false, 127 | autoread: true, 128 | autotyping: true, 129 | template: 'textMessage', 130 | } 131 | } 132 | 133 | if (typeof user !== 'object') global.db.users[m.sender] = {} 134 | if (user) { 135 | if (!('vip' in user)) user.afkReason = false 136 | if (!isNumber(user.afkTime)) user.afkTime = -1 137 | if (!('afkReason' in user)) user.afkReason = '' 138 | if (!isNumber(user.limit)) user.limit = limitUser 139 | if (!('uang' in user)) user.uang = uangUser 140 | if (!('lastclaim' in user)) user.lastclaim = new Date * 1 141 | if (!('lastbegal' in user)) user.lastbegal = new Date * 1 142 | if (!('lastrampok' in user)) user.lastrampok = new Date * 1 143 | } else { 144 | global.db.users[m.sender] = { 145 | vip: false, 146 | afkTime: -1, 147 | afkReason: '', 148 | limit: limitUser, 149 | uang: uangUser, 150 | lastclaim: new Date * 1, 151 | lastbegal: new Date * 1, 152 | lastrampok: new Date * 1, 153 | } 154 | } 155 | 156 | if (m.isGroup) { 157 | let group = global.db.groups[m.chat] 158 | if (typeof group !== 'object') global.db.groups[m.chat] = {} 159 | if (group) { 160 | if (!('nsfw' in group)) group.nsfw = false 161 | if (!('mute' in group)) group.mute = false 162 | if (!('setinfo' in group)) group.setinfo = true 163 | if (!('antilink' in group)) group.antilink = false 164 | if (!('antitoxic' in group)) group.antitoxic = false 165 | if (!('welcome' in group)) group.welcome = true 166 | if (!('antivirtex' in group)) group.antivirtex = false 167 | if (!('antidelete' in group)) group.antidelete = false 168 | if (!('waktusholat' in group)) group.waktusholat = false 169 | } else { 170 | global.db.groups[m.chat] = { 171 | nsfw: false, 172 | mute: false, 173 | setinfo: true, 174 | antilink: false, 175 | antitoxic: false, 176 | welcome: true, 177 | antivirtex: false, 178 | antidelete: false, 179 | waktusholat: false, 180 | } 181 | } 182 | } 183 | } catch (e) { 184 | throw e; 185 | } 186 | } 187 | 188 | async function MessagesUpsert(sych, message, store) { 189 | try { 190 | let botNumber = await sych.decodeJid(sych.user.id); 191 | const msg = message.messages[0]; 192 | if (store.groupMetadata && Object.keys(store.groupMetadata).length === 0) store.groupMetadata = await sych.groupFetchAllParticipating() 193 | const type = msg.message ? (getContentType(msg.message) || Object.keys(msg.message)[0]) : ''; 194 | if (!msg.key.fromMe && !msg.message && message.type === 'notify') return 195 | const m = await Serialize(sych, msg, store) 196 | require('../naze')(sych, m, message, store); 197 | if (type === 'interactiveResponseMessage' && m.quoted && m.quoted.fromMe) { 198 | await sych.appendResponseMessage(m, JSON.parse(m.msg.nativeFlowResponseMessage.paramsJson).id); 199 | } 200 | if (global.db.set && global.db.set[botNumber] && global.db.set[botNumber].readsw) { 201 | if (msg.key.remoteJid === 'status@broadcast') { 202 | await sych.readMessages([msg.key]); 203 | if (/protocolMessage/i.test(type)) sych.sendFromOwner(global.owner, 'Status dari @' + msg.key.participant.split('@')[0] + ' Telah dihapus', msg, { mentions: [msg.key.participant] }); 204 | if (/(audioMessage|imageMessage|videoMessage|extendedTextMessage)/i.test(type)) { 205 | let keke = (type == 'extendedTextMessage') ? `Story Teks Berisi : ${msg.message.extendedTextMessage.text ? msg.message.extendedTextMessage.text : ''}` : (type == 'imageMessage') ? `Story Gambar ${msg.message.imageMessage.caption ? 'dengan Caption : ' + msg.message.imageMessage.caption : ''}` : (type == 'videoMessage') ? `Story Video ${msg.message.videoMessage.caption ? 'dengan Caption : ' + msg.message.videoMessage.caption : ''}` : (type == 'audioMessage') ? 'Story Audio' : '\nTidak diketahui cek saja langsung' 206 | await sych.sendFromOwner(global.owner, `Melihat story dari @${msg.key.participant.split('@')[0]}\n${keke}`, msg, { mentions: [msg.key.participant] }); 207 | } 208 | } 209 | } 210 | } catch (e) { 211 | throw e; 212 | } 213 | } 214 | 215 | async function Solving(sych, store) { 216 | sych.serializeM = (m) => MessagesUpsert(sych, m, store) 217 | 218 | sych.decodeJid = (jid) => { 219 | if (!jid) return jid 220 | if (/:\d+@/gi.test(jid)) { 221 | let decode = jidDecode(jid) || {} 222 | return decode.user && decode.server && decode.user + '@' + decode.server || jid 223 | } else return jid 224 | } 225 | 226 | sych.getName = (jid, withoutContact = false) => { 227 | const id = sych.decodeJid(jid); 228 | if (id.endsWith('@g.us')) { 229 | const groupInfo = store.contacts[id] || sych.groupMetadata(id) || {}; 230 | return Promise.resolve(groupInfo.name || groupInfo.subject || PhoneNumber('+' + id.replace('@g.us', '')).getNumber('international')); 231 | } else { 232 | if (id === '0@s.whatsapp.net') { 233 | return 'WhatsApp'; 234 | } 235 | const contactInfo = store.contacts[id] || {}; 236 | return withoutContact ? '' : contactInfo.name || contactInfo.subject || contactInfo.verifiedName || PhoneNumber('+' + id.replace('@s.whatsapp.net', '')).getNumber('international'); 237 | } 238 | } 239 | 240 | sych.sendContact = async (jid, kon, quoted = '', opts = {}) => { 241 | let list = [] 242 | for (let i of kon) { 243 | list.push({ 244 | displayName: await sych.getName(i + '@s.whatsapp.net'), 245 | vcard: `BEGIN:VCARD\nVERSION:3.0\nN:${await sych.getName(i + '@s.whatsapp.net')}\nFN:${await sych.getName(i + '@s.whatsapp.net')}\nitem1.TEL;waid=${i}:${i}\nitem1.X-ABLabel:Ponsel\nitem2.ADR:;;Indonesia;;;;\nitem2.X-ABLabel:Region\nEND:VCARD` //vcard: `BEGIN:VCARD\nVERSION:3.0\nN:${await sych.getName(i + '@s.whatsapp.net')}\nFN:${await sych.getName(i + '@s.whatsapp.net')}\nitem1.TEL;waid=${i}:${i}\nitem1.X-ABLabel:Ponsel\nitem2.EMAIL;type=INTERNET:whatsapp@gmail.com\nitem2.X-ABLabel:Email\nitem3.URL:https://instagram.com/sych_dev\nitem3.X-ABLabel:Instagram\nitem4.ADR:;;Indonesia;;;;\nitem4.X-ABLabel:Region\nEND:VCARD` 246 | }) 247 | } 248 | sych.sendMessage(jid, { contacts: { displayName: `${list.length} Kontak`, contacts: list }, ...opts }, { quoted }) 249 | } 250 | 251 | sych.profilePictureUrl = async (jid, type = 'image', timeoutMs) => { 252 | const result = await sych.query({ 253 | tag: 'iq', 254 | attrs: { 255 | target: jidNormalizedUser(jid), 256 | to: '@s.whatsapp.net', 257 | type: 'get', 258 | xmlns: 'w:profile:picture' 259 | }, 260 | content: [{ 261 | tag: 'picture', 262 | attrs: { 263 | type, query: 'url' 264 | }, 265 | }] 266 | }, timeoutMs); 267 | const child = getBinaryNodeChild(result, 'picture'); 268 | return child?.attrs?.url; 269 | } 270 | 271 | sych.setStatus = (status) => { 272 | sych.query({ 273 | tag: 'iq', 274 | attrs: { 275 | to: '@s.whatsapp.net', 276 | type: 'set', 277 | xmlns: 'status', 278 | }, 279 | content: [{ 280 | tag: 'status', 281 | attrs: {}, 282 | content: Buffer.from(status, 'utf-8') 283 | }] 284 | }) 285 | return status 286 | } 287 | 288 | sych.sendPoll = (jid, name = '', values = [], selectableCount = 1) => { 289 | return sych.sendMessage(jid, { poll: { name, values, selectableCount }}) 290 | } 291 | 292 | sych.sendFileUrl = async (jid, url, caption, quoted, options = {}) => { 293 | async function getFileUrl(res, mime) { 294 | if (mime && mime.includes('gif')) { 295 | return sych.sendMessage(jid, { video: res.data, caption: caption, gifPlayback: true, ...options }, { quoted }); 296 | } else if (mime && mime === 'application/pdf') { 297 | return sych.sendMessage(jid, { document: res.data, mimetype: 'application/pdf', caption: caption, ...options }, { quoted }); 298 | } else if (mime && mime.includes('webp') && !/.jpg|.jpeg|.png/.test(url)) { 299 | return sych.sendAsSticker(jid, res.data, quoted, options); 300 | } else if (mime && mime.includes('image')) { 301 | return sych.sendMessage(jid, { image: res.data, caption: caption, ...options }, { quoted }); 302 | } else if (mime && mime.includes('video')) { 303 | return sych.sendMessage(jid, { video: res.data, caption: caption, mimetype: 'video/mp4', ...options }, { quoted }); 304 | } else if (mime && mime.includes('audio')) { 305 | return sych.sendMessage(jid, { audio: res.data, mimetype: 'audio/mpeg', ...options }, { quoted }); 306 | } 307 | } 308 | const axioss = axios.create({ 309 | httpsAgent: new https.Agent({ rejectUnauthorized: false }), 310 | }); 311 | const res = await axioss.get(url, { responseType: 'arraybuffer' }); 312 | let mime = res.headers['content-type']; 313 | if (!mime || mime.includes('octet-stream')) { 314 | const fileType = await FileType.fromBuffer(res.data); 315 | mime = fileType ? fileType.mime : null; 316 | } 317 | const hasil = await getFileUrl(res, mime); 318 | return hasil 319 | } 320 | 321 | sych.sendGroupInvite = async (jid, participant, inviteCode, inviteExpiration, groupName = 'Unknown Subject', caption = 'Invitation to join my WhatsApp group', jpegThumbnail = null, options = {}) => { 322 | const msg = proto.Message.fromObject({ 323 | groupInviteMessage: { 324 | inviteCode, 325 | inviteExpiration: parseInt(inviteExpiration) || + new Date(new Date + (3 * 86400000)), 326 | groupJid: jid, 327 | groupName, 328 | jpegThumbnail: Buffer.isBuffer(jpegThumbnail) ? jpegThumbnail : null, 329 | caption 330 | } 331 | }); 332 | const message = generateWAMessageFromContent(participant, msg, options); 333 | const invite = await sych.relayMessage(participant, message.message, { messageId: message.key.id }) 334 | return invite 335 | } 336 | 337 | sych.sendFromOwner = async (jid, text, quoted, options = {}) => { 338 | for (const a of jid) { 339 | await sych.sendMessage(a.replace(/[^0-9]/g, '') + '@s.whatsapp.net', { text, ...options }, { quoted }); 340 | } 341 | } 342 | 343 | sych.sendTextMentions = async (jid, text, quoted, options = {}) => sych.sendMessage(jid, { text: text, mentions: [...text.matchAll(/@(\d{0,16})/g)].map(v => v[1] + '@s.whatsapp.net'), ...options }, { quoted }) 344 | 345 | sych.sendAsSticker = async (jid, path, quoted, options = {}) => { 346 | const buff = Buffer.isBuffer(path) ? path : /^data:.*?\/.*?;base64,/i.test(path) ? Buffer.from(path.split`,`[1], 'base64') : /^https?:\/\//.test(path) ? await (await getBuffer(path)) : fs.existsSync(path) ? fs.readFileSync(path) : Buffer.alloc(0); 347 | const result = await writeExif(buff, options); 348 | return sych.sendMessage(jid, { sticker: { url: result }, ...options }, { quoted }); 349 | } 350 | 351 | sych.downloadMediaMessage = async (message) => { 352 | const msg = message.msg || message; 353 | const mime = msg.mimetype || ''; 354 | const messageType = (message.type || mime.split('/')[0]).replace(/Message/gi, ''); 355 | const stream = await downloadContentFromMessage(msg, messageType); 356 | let buffer = Buffer.from([]); 357 | for await (const chunk of stream) { 358 | buffer = Buffer.concat([buffer, chunk]); 359 | } 360 | return buffer 361 | } 362 | 363 | sych.downloadAndSaveMediaMessage = async (message, filename, attachExtension = true) => { 364 | const buffer = await sych.downloadMediaMessage(message); 365 | const type = await FileType.fromBuffer(buffer); 366 | const trueFileName = attachExtension ? `./database/sampah/${filename ? filename : Date.now()}.${type.ext}` : filename; 367 | await fs.promises.writeFile(trueFileName, buffer); 368 | return trueFileName; 369 | } 370 | 371 | sych.getFile = async (PATH, save) => { 372 | let res; 373 | let filename; 374 | let data = Buffer.isBuffer(PATH) ? PATH : /^data:.*?\/.*?;base64,/i.test(PATH) ? Buffer.from(PATH.split`,`[1], 'base64') : /^https?:\/\//.test(PATH) ? await (res = await getBuffer(PATH)) : fs.existsSync(PATH) ? (filename = PATH, fs.readFileSync(PATH)) : typeof PATH === 'string' ? PATH : Buffer.alloc(0) 375 | let type = await FileType.fromBuffer(data) || { mime: 'application/octet-stream', ext: '.bin' } 376 | filename = path.join(__dirname, '../database/sampah/' + new Date * 1 + '.' + type.ext) 377 | if (data && save) fs.promises.writeFile(filename, data) 378 | return { 379 | res, 380 | filename, 381 | size: await getSizeMedia(data), 382 | ...type, 383 | data 384 | } 385 | } 386 | 387 | sych.appendResponseMessage = async (m, text) => { 388 | let apb = await generateWAMessage(m.chat, { text, mentions: m.mentionedJid }, { userJid: sych.user.id, quoted: m.quoted }); 389 | apb.key = m.key 390 | apb.key.fromMe = areJidsSameUser(m.sender, sych.user.id); 391 | if (m.isGroup) apb.participant = m.sender; 392 | sych.ev.emit('messages.upsert', { 393 | ...m, 394 | messages: [proto.WebMessageInfo.fromObject(apb)], 395 | type: 'append' 396 | }); 397 | } 398 | 399 | sych.sendMedia = async (jid, path, fileName = '', caption = '', quoted = '', options = {}) => { 400 | const { mime, data, filename } = await sych.getFile(path, true); 401 | const isWebpSticker = options.asSticker || /webp/.test(mime); 402 | let type = 'document', mimetype = mime, pathFile = filename; 403 | if (isWebpSticker) { 404 | pathFile = await writeExif(data, { 405 | packname: options.packname || global.packname, 406 | author: options.author || global.author, 407 | categories: options.categories || [], 408 | }) 409 | await fs.unlinkSync(filename); 410 | type = 'sticker'; 411 | mimetype = 'image/webp'; 412 | } else if (/image|video|audio/.test(mime)) { 413 | type = mime.split('/')[0]; 414 | mimetype = type == 'video' ? 'video/mp4' : type == 'audio' ? 'audio/mpeg' : mime 415 | } 416 | let anu = await sych.sendMessage(jid, { [type]: { url: pathFile }, caption, mimetype, fileName, ...options }, { quoted, ...options }); 417 | await fs.unlinkSync(pathFile); 418 | return anu; 419 | } 420 | 421 | sych.sendButtonMsg = async (jid, content = {}, quoted, options = {}) => { 422 | const { text, caption, footer = '', title = '', contextInfo = {}, buttons = [], mentions = [], ...media } = content; 423 | const msg = await generateWAMessageFromContent(jid, { 424 | viewOnceMessage: { 425 | message: { 426 | messageContextInfo: { 427 | deviceListMetadata: {}, 428 | deviceListMetadataVersion: 2, 429 | }, 430 | interactiveMessage: proto.Message.InteractiveMessage.create({ 431 | body: proto.Message.InteractiveMessage.Body.create({ text: text || caption || '' }), 432 | footer: proto.Message.InteractiveMessage.Footer.create({ text: footer }), 433 | header: proto.Message.InteractiveMessage.Header.fromObject({ 434 | title, 435 | hasMediaAttachment: Object.keys(media).length > 0, 436 | ...(media && typeof media === 'object' && Object.keys(media).length > 0 ? await generateWAMessageContent(media, { 437 | upload: sych.waUploadToServer 438 | }) : {}) 439 | }), 440 | nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({ 441 | buttons: buttons.map(a => { 442 | return { 443 | name: a.name, 444 | buttonParamsJson: JSON.stringify(a.buttonParamsJson ? (typeof a.buttonParamsJson === 'string' ? JSON.parse(a.buttonParamsJson) : a.buttonParamsJson) : '') 445 | } 446 | }) 447 | }), 448 | contextInfo: { 449 | ...contextInfo, 450 | ...options.contextInfo, 451 | forwardingScore: 10, 452 | isForwarded: true, 453 | forwardedNewsletterMessageInfo: { 454 | newsletterJid: global.my.ch, 455 | serverMessageId: null, 456 | newsletterName: 'Join For More Info' 457 | }, 458 | mentionedJid: options.mentions || mentions, 459 | ...(quoted ? { 460 | stanzaId: quoted.key.id, 461 | remoteJid: quoted.key.remoteJid, 462 | participant: quoted.key.participant || quoted.key.remoteJid, 463 | fromMe: quoted.key.fromMe, 464 | quotedMessage: quoted.message 465 | } : {}) 466 | } 467 | }) 468 | } 469 | } 470 | }, {}); 471 | const hasil = await sych.relayMessage(msg.key.remoteJid, msg.message, { messageId: msg.key.id }); 472 | return hasil 473 | } 474 | 475 | sych.sendCarouselMsg = async (jid, body = '', footer = '', cards = [], options = {}) => { 476 | async function getImageMsg(url) { 477 | const { imageMessage } = await generateWAMessageContent({ image: { url } }, { upload: sych.waUploadToServer }); 478 | return imageMessage; 479 | } 480 | const cardPromises = cards.map(async (a) => { 481 | const imageMessage = await getImageMsg(a.url); 482 | return { 483 | header: { 484 | imageMessage: imageMessage, 485 | hasMediaAttachment: true 486 | }, 487 | body: { text: a.body }, 488 | footer: { text: a.footer }, 489 | nativeFlowMessage: { 490 | buttons: a.buttons.map(b => ({ 491 | name: b.name, 492 | buttonParamsJson: JSON.stringify(b.buttonParamsJson ? JSON.parse(b.buttonParamsJson) : '') 493 | })) 494 | } 495 | }; 496 | }); 497 | 498 | const cardResults = await Promise.all(cardPromises); 499 | const msg = await generateWAMessageFromContent(jid, { 500 | viewOnceMessage: { 501 | message: { 502 | messageContextInfo: { 503 | deviceListMetadata: {}, 504 | deviceListMetadataVersion: 2 505 | }, 506 | interactiveMessage: proto.Message.InteractiveMessage.create({ 507 | body: proto.Message.InteractiveMessage.Body.create({ text: body }), 508 | footer: proto.Message.InteractiveMessage.Footer.create({ text: footer }), 509 | carouselMessage: proto.Message.InteractiveMessage.CarouselMessage.create({ 510 | cards: cardResults, 511 | messageVersion: 1 512 | }) 513 | }) 514 | } 515 | } 516 | }, {}); 517 | const hasil = await sych.relayMessage(msg.key.remoteJid, msg.message, { messageId: msg.key.id }); 518 | return hasil 519 | } 520 | 521 | if (sych.user && sych.user.id) { 522 | const botNumber = sych.decodeJid(sych.user.id); 523 | if (global.db.set && global.db.set[botNumber]) { 524 | sych.public = global.db.set[botNumber].public 525 | } else sych.public = true 526 | } else sych.public = true 527 | 528 | return sych 529 | } 530 | 531 | /* 532 | * Create By sych 533 | * Follow https://github.com/sychdev 534 | * Whatsapp : https://whatsapp.com/channel/0029VaWOkNm7DAWtkvkJBK43 535 | */ 536 | 537 | async function Serialize(sych, m, store) { 538 | const botNumber = sych.decodeJid(sych.user.id) 539 | if (!m) return m 540 | if (m.key) { 541 | m.id = m.key.id 542 | m.chat = m.key.remoteJid 543 | m.fromMe = m.key.fromMe 544 | m.isBot = ['HSK', 'BAE', 'B1E', '3EB0', 'B24E', 'WA'].some(a => m.id.startsWith(a) && [12, 16, 20, 22, 40].includes(m.id.length)) || false 545 | m.isGroup = m.chat.endsWith('@g.us') 546 | m.sender = sych.decodeJid(m.fromMe && sych.user.id || m.participant || m.key.participant || m.chat || '') 547 | if (m.isGroup) { 548 | m.metadata = store.groupMetadata[m.chat] || await sych.groupMetadata(m.chat) 549 | m.admins = (m.metadata.participants.reduce((a, b) => (b.admin ? a.push({ id: b.id, admin: b.admin }) : [...a]) && a, [])) 550 | m.isAdmin = m.admins.some((b) => b.id === m.sender) 551 | m.participant = m.key.participant 552 | m.isBotAdmin = !!m.admins.find((member) => member.id === botNumber) 553 | } 554 | } 555 | if (m.message) { 556 | m.type = getContentType(m.message) || Object.keys(m.message)[0] 557 | m.msg = (/viewOnceMessage/i.test(m.type) ? m.message[m.type].message[getContentType(m.message[m.type].message)] : (extractMessageContent(m.message[m.type]) || m.message[m.type])) 558 | m.body = m.message?.conversation || m.msg?.text || m.msg?.conversation || m.msg?.caption || m.msg?.selectedButtonId || m.msg?.singleSelectReply?.selectedRowId || m.msg?.selectedId || m.msg?.contentText || m.msg?.selectedDisplayText || m.msg?.title || m.msg?.name || '' 559 | m.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] 560 | m.text = m.msg?.text || m.msg?.caption || m.message?.conversation || m.msg?.contentText || m.msg?.selectedDisplayText || m.msg?.title || ''; 561 | m.prefix = /^[°•π÷×¶∆£¢€¥®™+✓_=|~!?@#$%^&.©^]/gi.test(m.body) ? m.body.match(/^[°•π÷×¶∆£¢€¥®™+✓_=|~!?@#$%^&.©^]/gi)[0] : /[\uD800-\uDBFF][\uDC00-\uDFFF]/gi.test(m.body) ? m.body.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/gi)[0] : '' 562 | m.command = m.body && m.body.replace(m.prefix, '').trim().split(/ +/).shift() 563 | m.args = m.body?.trim().replace(new RegExp("^" + m.prefix?.replace(/[.*=+:\-?^${}()|[\]\\]|\s/g, '\\$&'), 'i'), '').replace(m.command, '').split(/ +/).filter(a => a) || [] 564 | m.device = getDevice(m.id) 565 | m.expiration = m.msg?.contextInfo?.expiration || 0 566 | m.timestamp = (typeof m.messageTimestamp === "number" ? m.messageTimestamp : m.messageTimestamp.low ? m.messageTimestamp.low : m.messageTimestamp.high) || m.msg.timestampMs * 1000 567 | m.isMedia = !!m.msg?.mimetype || !!m.msg?.thumbnailDirectPath 568 | if (m.isMedia) { 569 | m.mime = m.msg?.mimetype 570 | m.size = m.msg?.fileLength 571 | m.height = m.msg?.height || '' 572 | m.width = m.msg?.width || '' 573 | if (/webp/i.test(m.mime)) { 574 | m.isAnimated = m.msg?.isAnimated 575 | } 576 | } 577 | m.quoted = m.msg?.contextInfo?.quotedMessage || null 578 | if (m.quoted) { 579 | m.quoted.message = extractMessageContent(m.msg?.contextInfo?.quotedMessage) 580 | m.quoted.type = getContentType(m.quoted.message) || Object.keys(m.quoted.message)[0] 581 | m.quoted.id = m.msg.contextInfo.stanzaId 582 | m.quoted.device = getDevice(m.quoted.id) 583 | m.quoted.chat = m.msg.contextInfo.remoteJid || m.chat 584 | m.quoted.isBot = m.quoted.id ? ['HSK', 'BAE', 'B1E', '3EB0', 'B24E', 'WA'].some(a => m.quoted.id.startsWith(a) && [12, 16, 20, 22, 40].includes(m.quoted.id.length)) : false 585 | m.quoted.sender = sych.decodeJid(m.msg.contextInfo.participant) 586 | m.quoted.fromMe = m.quoted.sender === sych.decodeJid(sych.user.id) 587 | m.quoted.text = m.quoted.caption || m.quoted.conversation || m.quoted.contentText || m.quoted.selectedDisplayText || m.quoted.title || '' 588 | m.quoted.msg = extractMessageContent(m.quoted.message[m.quoted.type]) || m.quoted.message[m.quoted.type] 589 | m.quoted.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] 590 | m.quoted.body = m.quoted.msg?.text || m.quoted.msg?.caption || m.quoted?.message?.conversation || m.quoted.msg?.selectedButtonId || m.quoted.msg?.singleSelectReply?.selectedRowId || m.quoted.msg?.selectedId || m.quoted.msg?.contentText || m.quoted.msg?.selectedDisplayText || m.quoted.msg?.title || m.quoted?.msg?.name || '' 591 | m.getQuotedObj = async () => { 592 | if (!m.quoted.id) return false 593 | let q = await store.loadMessage(m.chat, m.quoted.id, sych) 594 | return await Serialize(sych, q, store) 595 | } 596 | m.quoted.key = { 597 | remoteJid: m.msg?.contextInfo?.remoteJid || m.chat, 598 | participant: m.quoted.sender, 599 | fromMe: areJidsSameUser(sych.decodeJid(m.msg?.contextInfo?.participant), sych.decodeJid(sych?.user?.id)), 600 | id: m.msg?.contextInfo?.stanzaId 601 | } 602 | m.quoted.isGroup = m.quoted.chat.endsWith('@g.us') 603 | m.quoted.mentions = m.quoted.msg?.contextInfo?.mentionedJid || [] 604 | m.quoted.body = m.quoted.msg?.text || m.quoted.msg?.caption || m.quoted?.message?.conversation || m.quoted.msg?.selectedButtonId || m.quoted.msg?.singleSelectReply?.selectedRowId || m.quoted.msg?.selectedId || m.quoted.msg?.contentText || m.quoted.msg?.selectedDisplayText || m.quoted.msg?.title || m.quoted?.msg?.name || '' 605 | m.quoted.prefix = /^[°•π÷×¶∆£¢€¥®™+✓_=|~!?@#$%^&.©^]/gi.test(m.quoted.body) ? m.quoted.body.match(/^[°•π÷×¶∆£¢€¥®™+✓_=|~!?@#$%^&.©^]/gi)[0] : /[\uD800-\uDBFF][\uDC00-\uDFFF]/gi.test(m.quoted.body) ? m.quoted.body.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/gi)[0] : '' 606 | m.quoted.command = m.quoted.body && m.quoted.body.replace(m.quoted.prefix, '').trim().split(/ +/).shift() 607 | m.quoted.isMedia = !!m.quoted.msg?.mimetype || !!m.quoted.msg?.thumbnailDirectPath 608 | if (m.quoted.isMedia) { 609 | m.quoted.mime = m.quoted.msg?.mimetype 610 | m.quoted.size = m.quoted.msg?.fileLength 611 | m.quoted.height = m.quoted.msg?.height || '' 612 | m.quoted.width = m.quoted.msg?.width || '' 613 | if (/webp/i.test(m.quoted.mime)) { 614 | m.quoted.isAnimated = m?.quoted?.msg?.isAnimated || false 615 | } 616 | } 617 | m.quoted.fakeObj = proto.WebMessageInfo.fromObject({ 618 | key: { 619 | remoteJid: m.quoted.chat, 620 | fromMe: m.quoted.fromMe, 621 | id: m.quoted.id 622 | }, 623 | message: m.quoted, 624 | ...(m.isGroup ? { participant: m.quoted.sender } : {}) 625 | }) 626 | m.quoted.download = () => sych.downloadMediaMessage(m.quoted) 627 | m.quoted.delete = () => { 628 | sych.sendMessage(m.quoted.chat, { 629 | delete: { 630 | remoteJid: m.quoted.chat, 631 | fromMe: m.isBotAdmins ? false : true, 632 | id: m.quoted.id, 633 | participant: m.quoted.sender 634 | } 635 | }) 636 | } 637 | } 638 | } 639 | 640 | m.download = () => sych.downloadMediaMessage(m) 641 | 642 | m.copy = () => Serialize(sych, proto.WebMessageInfo.fromObject(proto.WebMessageInfo.toObject(m))) 643 | 644 | m.reply = async (text, options = {}) => { 645 | const chatId = options?.chat ? options.chat : m.chat 646 | const caption = options.caption || ''; 647 | const quoted = options?.quoted ? options.quoted : m 648 | try { 649 | if (/^https?:\/\//.test(text)) { 650 | const data = await axios.get(text, { responseType: 'arraybuffer' }); 651 | const mime = data.headers['content-type'] || (await FileType.fromBuffer(data.data)).mime 652 | if (/gif|image|video|audio|pdf|stream/i.test(mime)) { 653 | return sych.sendMedia(chatId, data.data, '', caption, quoted, options) 654 | } else { 655 | return sych.sendMessage(chatId, { text: text, mentions: [...text.matchAll(/@(\d{0,16})/g)].map(v => v[1] + '@s.whatsapp.net'), ...options }, { quoted }) 656 | } 657 | } else { 658 | return sych.sendMessage(chatId, { text: text, mentions: [...text.matchAll(/@(\d{0,16})/g)].map(v => v[1] + '@s.whatsapp.net'), ...options }, { quoted }) 659 | } 660 | } catch (e) { 661 | return sych.sendMessage(chatId, { text: text, mentions: [...text.matchAll(/@(\d{0,16})/g)].map(v => v[1] + '@s.whatsapp.net'), ...options }, { quoted }) 662 | } 663 | } 664 | 665 | return m 666 | } 667 | 668 | module.exports = { GroupUpdate, GroupParticipantsUpdate, LoadDataBase, MessagesUpsert, Solving } 669 | 670 | let file = require.resolve(__filename) 671 | fs.watchFile(file, () => { 672 | fs.unwatchFile(file) 673 | console.log(chalk.redBright(`Update ${__filename}`)) 674 | delete require.cache[file] 675 | require(file) 676 | }); 677 | -------------------------------------------------------------------------------- /src/nulis/font/Indie-Flower.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/font/Indie-Flower.ttf -------------------------------------------------------------------------------- /src/nulis/font/ObelixProBIt-cyr.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/font/ObelixProBIt-cyr.ttf -------------------------------------------------------------------------------- /src/nulis/font/f: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/nulis/font/impact.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/font/impact.ttf -------------------------------------------------------------------------------- /src/nulis/images/buku/b: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/nulis/images/buku/sebelumkanan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/images/buku/sebelumkanan.jpg -------------------------------------------------------------------------------- /src/nulis/images/buku/sebelumkiri.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/images/buku/sebelumkiri.jpg -------------------------------------------------------------------------------- /src/nulis/images/folio/f: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/nulis/images/folio/sebelumkanan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/images/folio/sebelumkanan.jpg -------------------------------------------------------------------------------- /src/nulis/images/folio/sebelumkiri.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/src/nulis/images/folio/sebelumkiri.jpg -------------------------------------------------------------------------------- /src/nulis/images/i: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/nulis/nla: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/nulis/sychyy.json: -------------------------------------------------------------------------------- 1 | global.epep = ["62882008702155"]; 2 | global.name = { 3 | bot: "sychyy", 4 | own: "yudz" 5 | } 6 | -------------------------------------------------------------------------------- /src/premium.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 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 cekUser = _dir.find((user) => user.id == userId); 12 | if (cekUser) { 13 | cekUser.expired = cekUser.expired + toMs(expired); 14 | } else { 15 | const obj = { id: userId, expired: Date.now() + toMs(expired) }; 16 | _dir.push(obj); 17 | } 18 | fs.writeFileSync('./database/premium.json', JSON.stringify(_dir)); 19 | }; 20 | 21 | /** 22 | * Get premium user position. 23 | * @param {String} userId 24 | * @param {Object} _dir 25 | * @returns {Number} 26 | */ 27 | const getPremiumPosition = (userId, _dir) => { 28 | let position = null; 29 | Object.keys(_dir).forEach((i) => { 30 | if (_dir[i].id === userId) { 31 | position = i; 32 | } 33 | }); 34 | if (position !== null) { 35 | return position; 36 | } 37 | }; 38 | 39 | /** 40 | * Get premium user expire. 41 | * @param {String} userId 42 | * @param {Object} _dir 43 | * @returns {Number} 44 | */ 45 | const getPremiumExpired = (userId, _dir) => { 46 | let position = null; 47 | Object.keys(_dir).forEach((i) => { 48 | if (_dir[i].id === userId) { 49 | position = i; 50 | } 51 | }); 52 | if (position !== null) { 53 | return _dir[position].expired; 54 | } 55 | }; 56 | 57 | /** 58 | * Check user is premium. 59 | * @param {String} userId 60 | * @param {Object} _dir 61 | * @returns {Boolean} 62 | */ 63 | const checkPremiumUser = (userId, _dir) => { 64 | let status = false; 65 | Object.keys(_dir).forEach((i) => { 66 | if (_dir[i].id === userId) { 67 | status = true; 68 | } 69 | }); 70 | return status; 71 | }; 72 | 73 | /** 74 | * Constantly checking premium. 75 | * @param {Object} _dir 76 | */ 77 | const expiredCheck = (conn, _dir) => { 78 | setInterval(() => { 79 | let position = null; 80 | Object.keys(_dir).forEach((i) => { 81 | if (Date.now() >= _dir[i].expired) { 82 | position = i; 83 | } 84 | }); 85 | if (position !== null) { 86 | idny = _dir[position].id; 87 | console.log(`Premium expired: ${_dir[position].id}`); 88 | _dir.splice(position, 1); 89 | fs.writeFileSync('./database/premium.json', JSON.stringify(_dir)); 90 | idny ? conn.sendMessage(idny, { text: 'Premium Expired, Terima Kasih Sudah Berlangganan' }) : ''; 91 | idny = false; 92 | } 93 | }, 1000); 94 | }; 95 | 96 | /** 97 | * Get all premium user ID. 98 | * @param {Object} _dir 99 | * @returns {String[]} 100 | */ 101 | const getAllPremiumUser = (_dir) => { 102 | const array = []; 103 | Object.keys(_dir).forEach((i) => { 104 | array.push(_dir[i].id); 105 | }); 106 | return array; 107 | }; 108 | 109 | module.exports = { 110 | addPremiumUser, 111 | getPremiumExpired, 112 | getPremiumPosition, 113 | expiredCheck, 114 | checkPremiumUser, 115 | getAllPremiumUser, 116 | }; -------------------------------------------------------------------------------- /src/s: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/sewa.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const toMs = require('ms') 3 | 4 | /** 5 | * Add Sewa group. 6 | * @param {String} gid 7 | * @param {String} expired 8 | * @param {Object} _dir 9 | */ 10 | const addSewaGroup = (gid, expired, _dir) => { 11 | const obj = { id: gid, expired: Date.now() + toMs(expired), status: true } 12 | _dir.push(obj) 13 | fs.writeFileSync('./database/sewa.json', JSON.stringify(_dir, null, 2)) 14 | } 15 | 16 | /** 17 | * Get sewa group position. 18 | * @param {String} gid 19 | * @param {Object} _dir 20 | * @returns {Number} 21 | */ 22 | const getSewaPosition = (gid, _dir) => { 23 | let position = null 24 | Object.keys(_dir).forEach((i) => { 25 | if (_dir[i].id === gid) { 26 | position = i 27 | } 28 | }) 29 | if (position !== null) { 30 | return position 31 | } 32 | } 33 | 34 | /** 35 | * Get sewa group expire. 36 | * @param {String} gid 37 | * @param {Object} _dir 38 | * @returns {Number} 39 | */ 40 | const getSewaExpired = (gid, _dir) => { 41 | let position = null 42 | Object.keys(_dir).forEach((i) => { 43 | if (_dir[i].id === gid) { 44 | position = i 45 | } 46 | }) 47 | if (position !== null) { 48 | return _dir[position].expired 49 | } 50 | } 51 | 52 | /** 53 | * Check group is sewa. 54 | * @param {String} userId 55 | * @param {Object} _dir 56 | * @returns {Boolean} 57 | */ 58 | const checkSewaGroup = (gid, _dir) => { 59 | let status = false 60 | Object.keys(_dir).forEach((i) => { 61 | if (_dir[i].id === gid) { 62 | status = true 63 | } 64 | }) 65 | return status 66 | } 67 | 68 | /** 69 | * Constantly checking sewa. 70 | * @param {object} WAConnection 71 | * @param {Object} _dir 72 | */ 73 | const expiredCheck = (naze, _dir) => { 74 | setInterval(() => { 75 | let position = null 76 | Object.keys(_dir).forEach((i) => { 77 | if (Date.now() >= _dir[i].expired) { 78 | position = i 79 | } 80 | }) 81 | if (position !== null) { 82 | console.log(`Sewa expired: ${_dir[position].id}`) 83 | naze.sendMessage(_dir[position].id, { text: `Masa sewa di grup ini telah habis, bot otomatis keluar!` }) 84 | .then( res => { 85 | naze.groupLeave(_dir[position].id) 86 | _dir.splice(position, 1) 87 | fs.writeFileSync('./database/sewa.json', JSON.stringify(_dir, null, 2)) 88 | }) 89 | } 90 | }, 1000) 91 | } 92 | 93 | /** 94 | * Get all premium user ID. 95 | * @param {Object} _dir 96 | * @returns {String[]} 97 | */ 98 | const getAllPremiumUser = (_dir) => { 99 | const array = [] 100 | Object.keys(_dir).forEach((i) => { 101 | array.push(_dir[i].id) 102 | }) 103 | return array 104 | } 105 | 106 | module.exports = { 107 | addSewaGroup, 108 | getSewaExpired, 109 | getSewaPosition, 110 | expiredCheck, 111 | checkSewaGroup, 112 | getAllPremiumUser 113 | } -------------------------------------------------------------------------------- /start.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { spawn } = require('child_process'); 3 | 4 | function start() { 5 | let args = [path.join(__dirname, 'index.js'), ...process.argv.slice(2)] 6 | let p = spawn(process.argv[0], args, { 7 | stdio: ['inherit', 'inherit', 'inherit', 'ipc'] 8 | }).on('message', data => { 9 | if (data == 'reset') { 10 | console.log('Restarting Bot...') 11 | p.kill() 12 | start() 13 | delete p 14 | } else if (data == 'uptime') { 15 | p.send(process.uptime()) 16 | } 17 | }).on('exit', code => { 18 | console.error('Exited with code: ', code) 19 | if (code !== 0) start() 20 | }) 21 | } 22 | start() 23 | -------------------------------------------------------------------------------- /sychMedia/menu/audio.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/sychMedia/menu/audio.mp3 -------------------------------------------------------------------------------- /sychMedia/menu/gif.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/sychMedia/menu/gif.mp4 -------------------------------------------------------------------------------- /sychMedia/menu/sych.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/sychMedia/menu/sych.mp4 -------------------------------------------------------------------------------- /sychMedia/menu/sychy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/sychMedia/menu/sychy.jpg -------------------------------------------------------------------------------- /sychMedia/menu/sychyy.js: -------------------------------------------------------------------------------- 1 | [{ 2 | nameBot: "sychyyBotz", 3 | nameown: "yudaD0yy" 4 | }] 5 | -------------------------------------------------------------------------------- /sychMedia/sychyy.js: -------------------------------------------------------------------------------- 1 | [{ 2 | nameBot: "sychyyBotz", 3 | nameown: "yudaD0yy" 4 | }] 5 | -------------------------------------------------------------------------------- /temp_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sychyy/sychee/2800569c966e580ab28dd4f5edcc64156339d3b3/temp_image.png --------------------------------------------------------------------------------