├── Dockerfile ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── config.js ├── database ├── Naze ├── banned.json ├── premium.json └── stick │ └── Subscribe YT Naze ├── docker-compose.yml ├── index.js ├── lib ├── binary.js ├── cloudDBAdapter.js ├── converter.js ├── database.js ├── exif.js ├── jadibot.js ├── jadwaltv.js ├── lowdb │ ├── CAF │ ├── Low.d.ts │ ├── Low.js │ ├── LowSync.d.ts │ ├── LowSync.js │ ├── MissingAdapterError.d.ts │ ├── MissingAdapterError.js │ ├── adapters │ │ ├── CAF │ │ ├── JSONFile.d.ts │ │ ├── JSONFile.js │ │ ├── JSONFileSync.d.ts │ │ ├── JSONFileSync.js │ │ ├── LocalStorage.d.ts │ │ ├── LocalStorage.js │ │ ├── Memory.d.ts │ │ ├── Memory.js │ │ ├── MemorySync.d.ts │ │ ├── MemorySync.js │ │ ├── TextFile.d.ts │ │ ├── TextFile.js │ │ ├── TextFileSync.d.ts │ │ └── TextFileSync.js │ ├── index.d.ts │ └── index.js ├── mediafire.js ├── mongoDB.js ├── myfunc.js ├── premium.js ├── scraper.js ├── textpro.js ├── tictactoe.d.ts ├── tictactoe.js ├── uploader.js └── y2mate.js ├── media ├── doc │ ├── fake.doc │ ├── fake.pdf │ ├── fake.pptx │ └── fake.xlsx ├── image │ ├── fake.jpg │ └── naze.jpg └── nulis │ ├── font │ ├── Indie-Flower.ttf │ └── ObelixProBIt-cyr.ttf │ └── images │ ├── buku │ ├── sebelumkanan.jpg │ ├── sebelumkiri.jpg │ ├── setelahkanan.jpg │ └── setelahkiri.jpg │ └── folio │ ├── sebelumkanan.jpg │ ├── sebelumkiri.jpg │ ├── setelahkanan.jpg │ └── setelahkiri.jpg ├── naze.js ├── package.json ├── speed.py ├── src ├── database.json └── math.js └── yarn-error.log /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-buster 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y \ 5 | ffmpeg \ 6 | imagemagick \ 7 | webp && \ 8 | apt-get upgrade -y && \ 9 | rm -rf /var/lib/apt/lists/* 10 | 11 | COPY package.json . 12 | 13 | RUN npm install 14 | 15 | COPY . . 16 | 17 | CMD ["node", "."] 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Dika Ardnt. 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 | # CATATAN ( NOTE ) 2 | sc ini hanyalah hasil recode dari sc asli hisoka 3 | naze hanya menghilangkat bug, memperbagus & menyeting banyak hal 4 | agar tidak terjadi error 5 | 6 | #NazeMD 7 | Script WhatsApp Bot Multi Device 8 | 9 | ## NOTE 10 | This Script is for everyone, not for Sale. Jika dijual neraka menunggumu brother ! 11 | 12 |

13 | 14 |

15 |

NAZE DEV

16 | 17 | This is Script of WhatsApp multi device, working with [`@adiwajshing/baileys`](https://github.com/adiwajshing/baileys) 18 | 19 | ## My Project 20 | * New script to replace this script [`look here`](https://github.com/nazedev/naze-md) (`MULTI DEVICE `) 21 | * WhatsApp Bot normal [`DikaArdnt/Hisoka-Morrow`](https://github.com/DikaArdnt/Hisoka-Morrow) (SC ORI) 22 | * WhatsApp Bot Multi Device [`DikaArdnt/Hisoka-Morou`](https://github.com/DikaArdnt/Hisoka-Morou) 23 | * WhatsApp Bot Using Library whatsapp-web.js [`hisoka-waweb.js`](https://github.com/Hisoka-Morrou/hisoka-waweb.js/) 24 | 25 | 26 | ## UNTUK PENGGUNA WINDOWS/RDP 27 | 28 | * Unduh & Instal Git [`Klik Disini`](https://git-scm.com/downloads) 29 | * Unduh & Instal NodeJS [`Klik Disini`](https://nodejs.org/en/download) 30 | * Unduh & Instal FFmpeg [`Klik Disini`](https://ffmpeg.org/download.html) (**Jangan Lupa Tambahkan FFmpeg ke variabel lingkungan PATH**) 31 | 32 | 33 | ```bash 34 | git clone https://github.com/nazedev/naze-md 35 | cd naze 36 | npm install 37 | ``` 38 | 39 | ## HOW TO CONNECT TO MONGODB WHEN RUN IN HEROKU 40 | 41 | * Create account and database in mongodb atlas [`watch here`](https://youtu.be/w1iMJS0ib-w) 42 | * when you already have a database, you just need to take mongourl 43 | * Put mongourl in Procfile `web: node . --db 'mongourl'` 44 | * Example `web: node . -- db 'Your Mongo URI'` 45 | 46 | 47 | 48 | ## FOR TERMUX/UBUNTU/SSH USER 49 | 50 | ```bash 51 | apt update && apt upgrade 52 | apt install git -y 53 | apt install nodejs -y 54 | apt install ffmpeg -y 55 | git clone https://github.com/nazedev/naze-md 56 | cd naze 57 | npm install 58 | ``` 59 | 60 | ## RECOMMENDED INSTALL ON TERMUX 61 | 62 | ```bash 63 | pkg install yarn 64 | yarn 65 | ``` 66 | 67 | ## Installing 68 | ```bash 69 | $ node . 70 | ``` 71 | 72 | ## ❗ Warning 73 | Bot WhatsApp masih dalam tahap pengembangan, jadi ada beberapa bug 74 | Koneksi WhatsApp (BETA, tidak berfungsi dengan sempurna) 75 | 76 | Editing Number Owner in [`config.js`](https://github.com/nazedev/naze-md/blob/main/config.js) 77 | Get Apikey zenz on [`zenz`](https://zenzapi.xyz/pricing) 78 | 79 | 80 | ## Thanks To 81 | * [`@adiwajshing/baileys`](https://github.com/adiwajshing/baileys) 82 | * [`Nurutomo`](https://github.com/Nurutomo) 83 | * [`Mhankbarbar`](https://github.com/MhankBarBar) 84 | * [`Faiz`](https://github.com/FaizBastomi) 85 | * [`Gimenz`](https://github.com/Gimenz) 86 | * [`rayy`](https://github.com/rayyreall) 87 | * [`Fatih Arridho`](https://github.com/FatihArridho) 88 | * [`zhwzein`](https://github.com/zhwzein) 89 | * [`CAF-ID`](https://github.com/CAF-ID) 90 | * [`bintang`](https://github.com/Bintangp02) 91 | * [`ArullOfc`](https://github.com/Warikrr) 92 | * [`Naze Dev`](https://github.com/nazedev) 93 | 94 | ```Thanks to all who have participated in the development of this script``` 95 | 96 | 97 | License: [MIT](https://en.wikipedia.org/wiki/MIT_License) 98 | 99 | Support Me: 100 | * [`Saweria`](https://saweria.co/naze) 101 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "naze", 3 | "description": "WhatsApp Bot Using Lib Baileys", 4 | "repository": "https://github.com/nazedev/naze-md", 5 | "logo": "https://node-js-sample.herokuapp.com/node.png", 6 | "keywords": ["multi-device"] 7 | } 8 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create By Dika Ardnt. 3 | * Recode By Naze Dev 4 | * Contact Me on wa.me/6282113821188 5 | * Follow https://github.com/nazedev 6 | */ 7 | 8 | const fs = require('fs') 9 | const chalk = require('chalk') 10 | 11 | // Website Api 12 | global.APIs = { 13 | zenz: 'https://zenzapis.xyz', 14 | } 15 | 16 | // Apikey Website Api 17 | global.APIKeys = { 18 | 'https://zenzapis.xyz': '0e92565522', 19 | } 20 | 21 | // Other 22 | global.owner = ['6285875158363'] 23 | global.ownernomer = "6285875158363" 24 | global.premium = ['6285875158363'] 25 | global.packname = 'Sticker By' 26 | global.author = 'Naze Dev' 27 | global.sessionName = 'nazedev' //jangan diganti bro nanti error 28 | global.jumlha = '999' 29 | global.jumhal = '100000000000000' 30 | global.jumlah = '1000000000' 31 | global.prefa = ['','!','.','#','&'] 32 | global.sp = '' 33 | 34 | // Setting Mess 35 | global.mess = { 36 | success: '✅Done', 37 | admin: 'Fitur Khusus Admin Group!', 38 | botAdmin: 'Bot Harus Menjadi Admin Terlebih Dahulu!', 39 | premime: 'Fitur Khusus Premium Kalo Mau Daftar Ketik Sewa / Chat Owner', 40 | owner: 'Fitur Khusus Owner Bot', 41 | group: 'Fitur Digunakan Hanya Untuk Group!', 42 | private: 'Fitur Digunakan Hanya Untuk Private Chat!', 43 | bot: 'Fitur Khusus Pengguna Nomor Bot', 44 | wait: 'Loading...', 45 | error: 'Error!', 46 | errapi: 'Error Mungkin Apikey Tidak Valid!', 47 | errmor: 'Error Kesalahan Sistem', 48 | endLimit: 'Limit Harian Anda Telah Habis, Limit Akan Direset Setiap Jam 12', 49 | } 50 | 51 | // Limit 52 | global.limitawal = { 53 | premium: "Infinity", 54 | free: 25 55 | } 56 | 57 | // Fake 58 | global.thumb = fs.readFileSync('./media/image/naze.jpg') 59 | global.faall = fs.readFileSync('./media/image/fake.jpg') 60 | 61 | // Url 62 | global.mygit = 'https://github.com/nazedev' 63 | global.myyt = 'https://youtube.com/c/Nazedev' 64 | global.myytv = 'https://youtu.be/FAsL-Jy4qLc' 65 | global.mygc = "https://chat.whatsapp.com/Cp1OJenk6Q9D9vgLjLU558" 66 | 67 | // Engak Ngaruh, Belum Kepasang 68 | global.botname = 'NAZE BOT' 69 | global.akulaku = 'Bot By Naze' 70 | global.ytname = 'YT NAZE' //Kalo Ngk Punya Yt Ngak Usah Di Ganti 71 | 72 | 73 | let file = require.resolve(__filename) 74 | fs.watchFile(file, () => { 75 | fs.unwatchFile(file) 76 | console.log(chalk.redBright(`Update'${__filename}'`)) 77 | delete require.cache[file] 78 | require(file) 79 | }) 80 | -------------------------------------------------------------------------------- /database/Naze: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/banned.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /database/premium.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /database/stick/Subscribe YT Naze: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | web: 4 | build: . 5 | ports: 6 | - "8000:5000" 7 | volumes: 8 | - .:/code 9 | - logvolume01:/var/log 10 | links: 11 | - redis 12 | redis: 13 | image: redis 14 | volumes: 15 | logvolume01: {} -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create By Dika Ardnt. 3 | * Recode By Naze Dev 4 | * Contact Me on wa.me/6282113821188 5 | * Follow https://github.com/nazedev 6 | */ 7 | 8 | require('./config') 9 | const { default: nazeConnect, useSingleFileAuthState, DisconnectReason, fetchLatestBaileysVersion, generateForwardMessageContent, prepareWAMessageMedia, generateWAMessageFromContent, generateMessageID, downloadContentFromMessage, makeInMemoryStore, jidDecode, proto } = require("@adiwajshing/baileys") 10 | const { state, saveState } = useSingleFileAuthState(`./${sessionName}.json`) 11 | const pino = require('pino') 12 | const { Boom } = require('@hapi/boom') 13 | const fs = require('fs') 14 | const yargs = require('yargs/yargs') 15 | const chalk = require('chalk') 16 | const FileType = require('file-type') 17 | const path = require('path') 18 | const _ = require('lodash') 19 | const axios = require('axios') 20 | const PhoneNumber = require('awesome-phonenumber') 21 | const { imageToWebp, videoToWebp, writeExifImg, writeExifVid } = require('./lib/exif') 22 | const { smsg, isUrl, generateMessageTag, getBuffer, getSizeMedia, fetchJson, await, sleep } = require('./lib/myfunc') 23 | 24 | var low 25 | try { 26 | low = require('lowdb') 27 | } catch (e) { 28 | low = require('./lib/lowdb') 29 | } 30 | 31 | const { Low, JSONFile } = low 32 | const mongoDB = require('./lib/mongoDB') 33 | 34 | global.api = (name, path = '/', query = {}, apikeyqueryname) => (name in global.APIs ? global.APIs[name] : name) + path + (query || apikeyqueryname ? '?' + new URLSearchParams(Object.entries({ ...query, ...(apikeyqueryname ? { [apikeyqueryname]: global.APIKeys[name in global.APIs ? global.APIs[name] : name] } : {}) })) : '') 35 | 36 | const store = makeInMemoryStore({ logger: pino().child({ level: 'silent', stream: 'store' }) }) 37 | 38 | global.opts = new Object(yargs(process.argv.slice(2)).exitProcess(false).parse()) 39 | global.db = new Low( 40 | /https?:\/\//.test(opts['db'] || '') ? 41 | new cloudDBAdapter(opts['db']) : /mongodb/.test(opts['db']) ? 42 | new mongoDB(opts['db']) : 43 | new JSONFile(`src/database.json`) 44 | ) 45 | global.DATABASE = global.db // Backwards Compatibility 46 | global.loadDatabase = async function loadDatabase() { 47 | if (global.db.READ) return new Promise((resolve) => setInterval(function () { (!global.db.READ ? (clearInterval(this), resolve(global.db.data == null ? global.loadDatabase() : global.db.data)) : null) }, 1 * 1000)) 48 | if (global.db.data !== null) return 49 | global.db.READ = true 50 | await global.db.read() 51 | global.db.READ = false 52 | global.db.data = { 53 | users: {}, 54 | chats: {}, 55 | database: {}, 56 | game: {}, 57 | settings: {}, 58 | others: {}, 59 | sticker: {}, 60 | ...(global.db.data || {}) 61 | } 62 | global.db.chain = _.chain(global.db.data) 63 | } 64 | loadDatabase() 65 | 66 | // save database every 30seconds 67 | if (global.db) setInterval(async () => { 68 | if (global.db.data) await global.db.write() 69 | }, 30 * 1000) 70 | 71 | async function startNaze() { 72 | const naze = nazeConnect({ 73 | logger: pino({ level: 'silent' }), 74 | printQRInTerminal: true, 75 | browser: ['YT NAZE','Safari','1.0.0'], 76 | auth: state 77 | }) 78 | 79 | store.bind(naze.ev) 80 | 81 | // anticall auto block 82 | naze.ws.on('CB:call', async (json) => { 83 | const callerId = json.content[0].attrs['call-creator'] 84 | if (json.content[0].tag == 'offer') { 85 | let pa7rick = await naze.sendContact(callerId, global.owner) 86 | naze.sendMessage(callerId, { text: `*Sistem otomatis block!*\n*Jangan menelpon bot*!\n*Silahkan Hubungi Owner Untuk Dibuka !*`}, { quoted : pa7rick }) 87 | await sleep(8000) 88 | await naze.updateBlockStatus(callerId, "block") 89 | } 90 | }) 91 | 92 | naze.ev.on('messages.upsert', async chatUpdate => { 93 | //console.log(JSON.stringify(chatUpdate, undefined, 2)) 94 | try { 95 | mek = chatUpdate.messages[0] 96 | if (!mek.message) return 97 | mek.message = (Object.keys(mek.message)[0] === 'ephemeralMessage') ? mek.message.ephemeralMessage.message : mek.message 98 | if (mek.key && mek.key.remoteJid === 'status@broadcast') return 99 | if (!naze.public && !mek.key.fromMe && chatUpdate.type === 'notify') return 100 | if (mek.key.id.startsWith('BAE5') && mek.key.id.length === 16) return 101 | m = smsg(naze, mek, store) 102 | require("./naze")(naze, m, chatUpdate, store) 103 | } catch (err) { 104 | console.log(err) 105 | } 106 | }) 107 | 108 | // Group Update 109 | naze.ev.on('groups.update', async pea => { 110 | //console.log(pea) 111 | // Get Profile Picture Group 112 | try { 113 | ppgc = await naze.profilePictureUrl(pea[0].id, 'image') 114 | } catch { 115 | ppgc = 'https://shortlink.hisokaarridho.my.id/rg1oT' 116 | } 117 | let wm_nazedev = { url : ppgc } 118 | if (pea[0].announce == true) { 119 | naze.send5ButImg(pea[0].id, `「 *Group Settings Change* 」\n\nGroup telah ditutup oleh admin, Sekarang hanya admin yang dapat mengirim pesan !`, `Group Settings Change Message by Naze Dev`, wm_nazedev, []) 120 | } else if(pea[0].announce == false) { 121 | naze.send5ButImg(pea[0].id, `「 *Group Settings Change* 」\n\nGroup telah dibuka oleh admin, Sekarang peserta dapat mengirim pesan !`, `Group Settings Change Message by Naze Dev`, wm_nazedev, []) 122 | } else if (pea[0].restrict == true) { 123 | naze.send5ButImg(pea[0].id, `「 *Group Settings Change* 」\n\nInfo group telah dibatasi, Sekarang hanya admin yang dapat mengedit info group !`, `Group Settings Change Message by Naze Dev`, wm_nazedev, []) 124 | } else if (pea[0].restrict == false) { 125 | naze.send5ButImg(pea[0].id, `「 *Group Settings Change* 」\n\nInfo group telah dibuka, Sekarang peserta dapat mengedit info group !`, `Group Settings Change Message by Naze Dev`, wm_nazedev, []) 126 | } else { 127 | naze.send5ButImg(pea[0].id, `「 *Group Settings Change* 」\n\nGroup Subject telah diganti menjadi *${pea[0].subject}*`, `Group Settings Change Message by Naze Dev`, wm_nazedev, []) 128 | } 129 | }) 130 | 131 | naze.ev.on('group-participants.update', async (anu) => { 132 | console.log(anu) 133 | try { 134 | let metadata = await naze.groupMetadata(anu.id) 135 | let participants = anu.participants 136 | for (let num of participants) { 137 | // Get Profile Picture User 138 | try { 139 | ppuser = await naze.profilePictureUrl(num, 'image') 140 | } catch { 141 | ppuser = 'https://i0.wp.com/www.gambarunik.id/wp-content/uploads/2019/06/Top-Gambar-Foto-Profil-Kosong-Lucu-Tergokil-.jpg' 142 | } 143 | 144 | //Resize 145 | const reSize = async(buffer, ukur1, ukur2) => { 146 | return new Promise(async(resolve, reject) => { 147 | let jimp = require('jimp') 148 | var baper = await jimp.read(buffer); 149 | var ab = await baper.resize(ukur1, ukur2).getBufferAsync(jimp.MIME_JPEG) 150 | resolve(ab) 151 | }) 152 | } 153 | 154 | // Get Profile Picture Group 155 | try { 156 | ppgroup = await naze.profilePictureUrl(anu.id, 'image') 157 | } catch { 158 | ppgroup = 'https://i0.wp.com/www.gambarunik.id/wp-content/uploads/2019/06/Top-Gambar-Foto-Profil-Kosong-Lucu-Tergokil-.jpg' 159 | } 160 | 161 | let butwel = [{ buttonId: 'menu', buttonText: { displayText: 'WELCOME' }, type: 1 }] 162 | let butleav = [{ buttonId: 'subsyt', buttonText: { displayText: 'Sayonara👋' }, type: 1 }] 163 | let butselamat = [{ buttonId: '', buttonText: { displayText: 'SELAMAT' }, type: 1 }] 164 | let butsebar = [{ buttonId: '', buttonText: { displayText: 'SABAR' }, type: 1 }] 165 | let nyoutube = ('© Naze\nYoutube/Sc :\nhttps://youtube.com/c/Nazedev') 166 | let teks1 = `*Halo Kak @${num.split('@')[0]}*\n*Selamat Datang Di Grup*\n*${metadata.subject}*\n*Jangan Lupa Intro Yahh*\n_~Admin_` 167 | let teks2 = `*Selamat Tinggal Kak @${num.split('@')[0]}*\n*Semoga Tenang Di Alam Sana*\n_~Admin_` 168 | let teks3 = `*@${num.split('@')[0]} Promote From*\n*${metadata.subject}*\n*Selamat Anda Menjadi Admin*\n_~Jangan Semena Mena!_` 169 | let teks4 = `*@${num.split('@')[0]} Demote From*\n*${metadata.subject}*\n_Kasihan Turun Pangkat🤭_` 170 | if (anu.action == 'add') { 171 | naze.sendMessage(anu.id, { caption: teks1, location: { jpegThumbnail: await reSize(ppuser, 100, 100)}, buttons: butwel, footer: nyoutube, mentions: [num] }) 172 | } else if (anu.action == 'remove') { 173 | naze.sendMessage(anu.id, { caption: teks2, location: { jpegThumbnail: await reSize(ppuser, 100, 100)}, buttons: butleav, footer: nyoutube, mentions: [num] }) 174 | } else if (anu.action == 'promote') { 175 | naze.sendMessage(anu.id, { caption: teks3, location: { jpegThumbnail: await reSize(ppuser, 100, 100)}, buttons: butselamat, footer: nyoutube, mentions: [num] }) 176 | } else if (anu.action == 'demote') { 177 | naze.sendMessage(anu.id, { caption: teks4, location: { jpegThumbnail: await reSize(ppuser, 100, 100)}, buttons: butsebar, footer: nyoutube, mentions: [num] }) 178 | } 179 | } 180 | } catch (err) { 181 | console.log(err) 182 | } 183 | }) 184 | 185 | // Setting 186 | naze.decodeJid = (jid) => { 187 | if (!jid) return jid 188 | if (/:\d+@/gi.test(jid)) { 189 | let decode = jidDecode(jid) || {} 190 | return decode.user && decode.server && decode.user + '@' + decode.server || jid 191 | } else return jid 192 | } 193 | 194 | naze.ev.on('contacts.update', update => { 195 | for (let contact of update) { 196 | let id = naze.decodeJid(contact.id) 197 | if (store && store.contacts) store.contacts[id] = { id, name: contact.notify } 198 | } 199 | }) 200 | 201 | naze.getName = (jid, withoutContact = false) => { 202 | id = naze.decodeJid(jid) 203 | withoutContact = naze.withoutContact || withoutContact 204 | let v 205 | if (id.endsWith("@g.us")) return new Promise(async (resolve) => { 206 | v = store.contacts[id] || {} 207 | if (!(v.name || v.subject)) v = naze.groupMetadata(id) || {} 208 | resolve(v.name || v.subject || PhoneNumber('+' + id.replace('@s.whatsapp.net', '')).getNumber('international')) 209 | }) 210 | else v = id === '0@s.whatsapp.net' ? { 211 | id, 212 | name: 'WhatsApp' 213 | } : id === naze.decodeJid(naze.user.id) ? 214 | naze.user : 215 | (store.contacts[id] || {}) 216 | return (withoutContact ? '' : v.name) || v.subject || v.verifiedName || PhoneNumber('+' + jid.replace('@s.whatsapp.net', '')).getNumber('international') 217 | } 218 | 219 | naze.sendContact = async (jid, kon, quoted = '', opts = {}) => { 220 | let list = [] 221 | for (let i of kon) { 222 | list.push({ 223 | displayName: await naze.getName(i + '@s.whatsapp.net'), 224 | vcard: `BEGIN:VCARD\nVERSION:3.0\nN:${await naze.getName(i + '@s.whatsapp.net')}\nFN:${await naze.getName(i + '@s.whatsapp.net')}\nitem1.TEL;waid=${i}:${i}\nitem1.X-ABLabel:Ponsel\nitem2.EMAIL;type=INTERNET:nazedev@gmail.com\nitem2.X-ABLabel:Email\nitem3.URL:https://instagram.com/naze.dev\nitem3.X-ABLabel:Instagram\nitem4.ADR:;;Indonesia;;;;\nitem4.X-ABLabel:Region\nEND:VCARD` 225 | }) 226 | } 227 | naze.sendMessage(jid, { contacts: { displayName: `${list.length} Kontak`, contacts: list }, ...opts }, { quoted }) 228 | } 229 | 230 | naze.setStatus = (status) => { 231 | naze.query({ 232 | tag: 'iq', 233 | attrs: { 234 | to: '@s.whatsapp.net', 235 | type: 'set', 236 | xmlns: 'status', 237 | }, 238 | content: [{ 239 | tag: 'status', 240 | attrs: {}, 241 | content: Buffer.from(status, 'utf-8') 242 | }] 243 | }) 244 | return status 245 | } 246 | 247 | naze.public = true 248 | 249 | naze.serializeM = (m) => smsg(naze, m, store) 250 | 251 | naze.ev.on('connection.update', async (update) => { 252 | const { connection, lastDisconnect } = update 253 | if (connection === 'close') { 254 | let reason = new Boom(lastDisconnect?.error)?.output.statusCode 255 | if (reason === DisconnectReason.badSession) { console.log(`Bad Session File, Please Delete Session and Scan Again`); naze.logout(); } 256 | else if (reason === DisconnectReason.connectionClosed) { console.log("Connection closed, reconnecting...."); startNaze(); } 257 | else if (reason === DisconnectReason.connectionLost) { console.log("Connection Lost from Server, reconnecting..."); startNaze(); } 258 | else if (reason === DisconnectReason.connectionReplaced) { console.log("Connection Replaced, Another New Session Opened, Please Close Current Session First"); naze.logout(); } 259 | else if (reason === DisconnectReason.loggedOut) { console.log(`Device Logged Out, Please Scan Again And Run.`); naze.logout(); } 260 | else if (reason === DisconnectReason.restartRequired) { console.log("Restart Required, Restarting..."); startNaze(); } 261 | else if (reason === DisconnectReason.timedOut) { console.log("Connection TimedOut, Reconnecting..."); startNaze(); } 262 | else naze.end(`Unknown DisconnectReason: ${reason}|${connection}`) 263 | } 264 | console.log('Connected...', update) 265 | }) 266 | 267 | naze.ev.on('creds.update', saveState) 268 | 269 | /** Resize Image 270 | * 271 | * @param {Buffer} Buffer (Only Image) 272 | * @param {Numeric} Width 273 | * @param {Numeric} Height 274 | */ 275 | naze.reSize = async (image, width, height) => { 276 | let jimp = require('jimp') 277 | var oyy = await jimp.read(image); 278 | var kiyomasa = await oyy.resize(width, height).getBufferAsync(jimp.MIME_JPEG) 279 | return kiyomasa 280 | } 281 | 282 | // Add Other 283 | 284 | /** 285 | * 286 | * @param {*} jid 287 | * @param {*} url 288 | * @param {*} caption 289 | * @param {*} quoted 290 | * @param {*} options 291 | */ 292 | naze.sendFileUrl = async (jid, url, caption, quoted, options = {}) => { 293 | let mime = ''; 294 | let res = await axios.head(url) 295 | mime = res.headers['content-type'] 296 | if (mime.split("/")[1] === "gif") { 297 | return naze.sendMessage(jid, { video: await getBuffer(url), caption: caption, gifPlayback: true, ...options}, { quoted: quoted, ...options}) 298 | } 299 | let type = mime.split("/")[0]+"Message" 300 | if(mime === "application/pdf"){ 301 | return naze.sendMessage(jid, { document: await getBuffer(url), mimetype: 'application/pdf', caption: caption, ...options}, { quoted: quoted, ...options }) 302 | } 303 | if(mime.split("/")[0] === "image"){ 304 | return naze.sendMessage(jid, { image: await getBuffer(url), caption: caption, ...options}, { quoted: quoted, ...options}) 305 | } 306 | if(mime.split("/")[0] === "video"){ 307 | return naze.sendMessage(jid, { video: await getBuffer(url), caption: caption, mimetype: 'video/mp4', ...options}, { quoted: quoted, ...options }) 308 | } 309 | if(mime.split("/")[0] === "audio"){ 310 | return naze.sendMessage(jid, { audio: await getBuffer(url), caption: caption, mimetype: 'audio/mpeg', ...options}, { quoted: quoted, ...options }) 311 | } 312 | } 313 | 314 | /** Send List Messaage 315 | * 316 | *@param {*} jid 317 | *@param {*} text 318 | *@param {*} footer 319 | *@param {*} title 320 | *@param {*} butText 321 | *@param [*] sections 322 | *@param {*} quoted 323 | */ 324 | naze.sendListMsg = (jid, text = '', footer = '', title = '' , butText = '', sects = [], quoted) => { 325 | let sections = sects 326 | var listMes = { 327 | text: text, 328 | footer: footer, 329 | title: title, 330 | buttonText: butText, 331 | sections 332 | } 333 | naze.sendMessage(jid, listMes, { quoted: quoted }) 334 | } 335 | 336 | /** Send Button 5 Location 337 | * 338 | * @param {*} jid 339 | * @param {*} text 340 | * @param {*} footer 341 | * @param {*} location 342 | * @param [*] button 343 | * @param {*} options 344 | */ 345 | naze.send5ButLoc = async (jid , text = '' , footer = '', lok, but = [], options = {}) =>{ 346 | let bb = await naze.reSize(lok, 300, 300) 347 | naze.sendMessage(jid, { location: { jpegThumbnail: bb }, caption: text, footer: footer, templateButtons: but, ...options }) 348 | } 349 | 350 | /** Send Button 5 Message 351 | * 352 | * @param {*} jid 353 | * @param {*} text 354 | * @param {*} footer 355 | * @param {*} button 356 | * @returns 357 | */ 358 | naze.send5ButMsg = (jid, text = '' , footer = '', but = []) =>{ 359 | let templateButtons = but 360 | var templateMessage = { 361 | text: text, 362 | footer: footer, 363 | templateButtons: templateButtons 364 | } 365 | naze.sendMessage(jid, templateMessage) 366 | } 367 | 368 | /** Send Button 5 Image 369 | * 370 | * @param {*} jid 371 | * @param {*} text 372 | * @param {*} footer 373 | * @param {*} image 374 | * @param [*] button 375 | * @param {*} options 376 | * @returns 377 | */ 378 | naze.send5ButImg = async (jid , text = '' , footer = '', img, but = [], options = {}) =>{ 379 | let message = await prepareWAMessageMedia({ image: img }, { upload: naze.waUploadToServer }) 380 | var template = generateWAMessageFromContent(jid, proto.Message.fromObject({ 381 | templateMessage: { 382 | hydratedTemplate: { 383 | imageMessage: message.imageMessage, 384 | "hydratedContentText": text, 385 | "hydratedFooterText": footer, 386 | "hydratedButtons": but 387 | } 388 | } 389 | }), options) 390 | naze.relayMessage(jid, template.message, { messageId: template.key.id }) 391 | } 392 | 393 | /** Send Button 5 Video 394 | * 395 | * @param {*} jid 396 | * @param {*} text 397 | * @param {*} footer 398 | * @param {*} Video 399 | * @param [*] button 400 | * @param {*} options 401 | * @returns 402 | */ 403 | naze.send5ButVid = async (jid , text = '' , footer = '', vid, but = [], options = {}) =>{ 404 | let message = await prepareWAMessageMedia({ video: vid }, { upload: naze.waUploadToServer }) 405 | var template = generateWAMessageFromContent(jid, proto.Message.fromObject({ 406 | templateMessage: { 407 | hydratedTemplate: { 408 | videoMessage: message.videoMessage, 409 | "hydratedContentText": text, 410 | "hydratedFooterText": footer, 411 | "hydratedButtons": but 412 | } 413 | } 414 | }), options) 415 | naze.relayMessage(jid, template.message, { messageId: template.key.id }) 416 | } 417 | 418 | /** Send Button 5 Gif 419 | * 420 | * @param {*} jid 421 | * @param {*} text 422 | * @param {*} footer 423 | * @param {*} Gif 424 | * @param [*] button 425 | * @param {*} options 426 | * @returns 427 | */ 428 | naze.send5ButGif = async (jid , text = '' , footer = '', gif, but = [], options = {}) =>{ 429 | let message = await prepareWAMessageMedia({ video: gif, gifPlayback: true }, { upload: naze.waUploadToServer }) 430 | var template = generateWAMessageFromContent(jid, proto.Message.fromObject({ 431 | templateMessage: { 432 | hydratedTemplate: { 433 | videoMessage: message.videoMessage, 434 | "hydratedContentText": text, 435 | "hydratedFooterText": footer, 436 | "hydratedButtons": but 437 | } 438 | } 439 | }), options) 440 | naze.relayMessage(jid, template.message, { messageId: template.key.id }) 441 | } 442 | 443 | /** 444 | * 445 | * @param {*} jid 446 | * @param {*} buttons 447 | * @param {*} caption 448 | * @param {*} footer 449 | * @param {*} quoted 450 | * @param {*} options 451 | */ 452 | naze.sendButtonText = (jid, buttons = [], text, footer, quoted = '', options = {}) => { 453 | let buttonMessage = { 454 | text, 455 | footer, 456 | buttons, 457 | headerType: 2, 458 | ...options 459 | } 460 | naze.sendMessage(jid, buttonMessage, { quoted, ...options }) 461 | } 462 | 463 | /** 464 | * 465 | * @param {*} jid 466 | * @param {*} text 467 | * @param {*} quoted 468 | * @param {*} options 469 | * @returns 470 | */ 471 | naze.sendText = (jid, text, quoted = '', options) => naze.sendMessage(jid, { text: text, ...options }, { quoted }) 472 | 473 | /** 474 | * 475 | * @param {*} jid 476 | * @param {*} path 477 | * @param {*} caption 478 | * @param {*} quoted 479 | * @param {*} options 480 | * @returns 481 | */ 482 | naze.sendImage = async (jid, path, caption = '', quoted = '', options) => { 483 | let buffer = 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) 484 | return await naze.sendMessage(jid, { image: buffer, caption: caption, ...options }, { quoted }) 485 | } 486 | 487 | /** 488 | * 489 | * @param {*} jid 490 | * @param {*} path 491 | * @param {*} caption 492 | * @param {*} quoted 493 | * @param {*} options 494 | * @returns 495 | */ 496 | naze.sendVideo = async (jid, path, caption = '', quoted = '', gif = false, options) => { 497 | let buffer = 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) 498 | return await naze.sendMessage(jid, { video: buffer, caption: caption, gifPlayback: gif, ...options }, { quoted }) 499 | } 500 | 501 | /** 502 | * 503 | * @param {*} jid 504 | * @param {*} path 505 | * @param {*} quoted 506 | * @param {*} mime 507 | * @param {*} options 508 | * @returns 509 | */ 510 | naze.sendAudio = async (jid, path, quoted = '', ptt = false, options) => { 511 | let buffer = 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) 512 | return await naze.sendMessage(jid, { audio: buffer, ptt: ptt, ...options }, { quoted }) 513 | } 514 | 515 | /** 516 | * 517 | * @param {*} jid 518 | * @param {*} text 519 | * @param {*} quoted 520 | * @param {*} options 521 | * @returns 522 | */ 523 | naze.sendTextWithMentions = async (jid, text, quoted, options = {}) => naze.sendMessage(jid, { text: text, contextInfo: { mentionedJid: [...text.matchAll(/@(\d{0,16})/g)].map(v => v[1] + '@s.whatsapp.net') }, ...options }, { quoted }) 524 | 525 | /** 526 | * 527 | * @param {*} jid 528 | * @param {*} path 529 | * @param {*} quoted 530 | * @param {*} options 531 | * @returns 532 | */ 533 | naze.sendImageAsSticker = async (jid, path, quoted, options = {}) => { 534 | let 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) 535 | let buffer 536 | if (options && (options.packname || options.author)) { 537 | buffer = await writeExifImg(buff, options) 538 | } else { 539 | buffer = await imageToWebp(buff) 540 | } 541 | 542 | await naze.sendMessage(jid, { sticker: { url: buffer }, ...options }, { quoted }) 543 | return buffer 544 | } 545 | 546 | /** 547 | * 548 | * @param {*} jid 549 | * @param {*} path 550 | * @param {*} quoted 551 | * @param {*} options 552 | * @returns 553 | */ 554 | naze.sendVideoAsSticker = async (jid, path, quoted, options = {}) => { 555 | let 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) 556 | let buffer 557 | if (options && (options.packname || options.author)) { 558 | buffer = await writeExifVid(buff, options) 559 | } else { 560 | buffer = await videoToWebp(buff) 561 | } 562 | 563 | await naze.sendMessage(jid, { sticker: { url: buffer }, ...options }, { quoted }) 564 | return buffer 565 | } 566 | 567 | /** 568 | * 569 | * @param {*} message 570 | * @param {*} filename 571 | * @param {*} attachExtension 572 | * @returns 573 | */ 574 | naze.downloadAndSaveMediaMessage = async (message, filename, attachExtension = true) => { 575 | let quoted = message.msg ? message.msg : message 576 | let mime = (message.msg || message).mimetype || '' 577 | let messageType = message.mtype ? message.mtype.replace(/Message/gi, '') : mime.split('/')[0] 578 | const stream = await downloadContentFromMessage(quoted, messageType) 579 | let buffer = Buffer.from([]) 580 | for await(const chunk of stream) { 581 | buffer = Buffer.concat([buffer, chunk]) 582 | } 583 | let type = await FileType.fromBuffer(buffer) 584 | trueFileName = attachExtension ? (filename + '.' + type.ext) : filename 585 | // save to file 586 | await fs.writeFileSync(trueFileName, buffer) 587 | return trueFileName 588 | } 589 | 590 | naze.downloadMediaMessage = async (message) => { 591 | let mime = (message.msg || message).mimetype || '' 592 | let messageType = message.mtype ? message.mtype.replace(/Message/gi, '') : mime.split('/')[0] 593 | const stream = await downloadContentFromMessage(message, messageType) 594 | let buffer = Buffer.from([]) 595 | for await(const chunk of stream) { 596 | buffer = Buffer.concat([buffer, chunk]) 597 | } 598 | 599 | return buffer 600 | } 601 | 602 | /** 603 | * 604 | * @param {*} jid 605 | * @param {*} path 606 | * @param {*} filename 607 | * @param {*} caption 608 | * @param {*} quoted 609 | * @param {*} options 610 | * @returns 611 | */ 612 | naze.sendMedia = async (jid, path, fileName = '', caption = '', quoted = '', options = {}) => { 613 | let types = await naze.getFile(path, true) 614 | let { mime, ext, res, data, filename } = types 615 | if (res && res.status !== 200 || file.length <= 65536) { 616 | try { throw { json: JSON.parse(file.toString()) } } 617 | catch (e) { if (e.json) throw e.json } 618 | } 619 | let type = '', mimetype = mime, pathFile = filename 620 | if (options.asDocument) type = 'document' 621 | if (options.asSticker || /webp/.test(mime)) { 622 | let { writeExif } = require('./lib/exif') 623 | let media = { mimetype: mime, data } 624 | pathFile = await writeExif(media, { packname: options.packname ? options.packname : global.packname, author: options.author ? options.author : global.author, categories: options.categories ? options.categories : [] }) 625 | await fs.promises.unlink(filename) 626 | type = 'sticker' 627 | mimetype = 'image/webp' 628 | } 629 | else if (/image/.test(mime)) type = 'image' 630 | else if (/video/.test(mime)) type = 'video' 631 | else if (/audio/.test(mime)) type = 'audio' 632 | else type = 'document' 633 | await naze.sendMessage(jid, { [type]: { url: pathFile }, caption, mimetype, fileName, ...options }, { quoted, ...options }) 634 | return fs.promises.unlink(pathFile) 635 | } 636 | 637 | /** 638 | * 639 | * @param {*} jid 640 | * @param {*} message 641 | * @param {*} forceForward 642 | * @param {*} options 643 | * @returns 644 | */ 645 | naze.copyNForward = async (jid, message, forceForward = false, options = {}) => { 646 | let vtype 647 | if (options.readViewOnce) { 648 | message.message = message.message && message.message.ephemeralMessage && message.message.ephemeralMessage.message ? message.message.ephemeralMessage.message : (message.message || undefined) 649 | vtype = Object.keys(message.message.viewOnceMessage.message)[0] 650 | delete(message.message && message.message.ignore ? message.message.ignore : (message.message || undefined)) 651 | delete message.message.viewOnceMessage.message[vtype].viewOnce 652 | message.message = { 653 | ...message.message.viewOnceMessage.message 654 | } 655 | } 656 | 657 | let mtype = Object.keys(message.message)[0] 658 | let content = await generateForwardMessageContent(message, forceForward) 659 | let ctype = Object.keys(content)[0] 660 | let context = {} 661 | if (mtype != "conversation") context = message.message[mtype].contextInfo 662 | content[ctype].contextInfo = { 663 | ...context, 664 | ...content[ctype].contextInfo 665 | } 666 | const waMessage = await generateWAMessageFromContent(jid, content, options ? { 667 | ...content[ctype], 668 | ...options, 669 | ...(options.contextInfo ? { 670 | contextInfo: { 671 | ...content[ctype].contextInfo, 672 | ...options.contextInfo 673 | } 674 | } : {}) 675 | } : {}) 676 | await naze.relayMessage(jid, waMessage.message, { messageId: waMessage.key.id }) 677 | return waMessage 678 | } 679 | 680 | naze.cMod = (jid, copy, text = '', sender = naze.user.id, options = {}) => { 681 | //let copy = message.toJSON() 682 | let mtype = Object.keys(copy.message)[0] 683 | let isEphemeral = mtype === 'ephemeralMessage' 684 | if (isEphemeral) { 685 | mtype = Object.keys(copy.message.ephemeralMessage.message)[0] 686 | } 687 | let msg = isEphemeral ? copy.message.ephemeralMessage.message : copy.message 688 | let content = msg[mtype] 689 | if (typeof content === 'string') msg[mtype] = text || content 690 | else if (content.caption) content.caption = text || content.caption 691 | else if (content.text) content.text = text || content.text 692 | if (typeof content !== 'string') msg[mtype] = { 693 | ...content, 694 | ...options 695 | } 696 | if (copy.key.participant) sender = copy.key.participant = sender || copy.key.participant 697 | else if (copy.key.participant) sender = copy.key.participant = sender || copy.key.participant 698 | if (copy.key.remoteJid.includes('@s.whatsapp.net')) sender = sender || copy.key.remoteJid 699 | else if (copy.key.remoteJid.includes('@broadcast')) sender = sender || copy.key.remoteJid 700 | copy.key.remoteJid = jid 701 | copy.key.fromMe = sender === naze.user.id 702 | 703 | return proto.WebMessageInfo.fromObject(copy) 704 | } 705 | 706 | 707 | /** 708 | * 709 | * @param {*} path 710 | * @returns 711 | */ 712 | naze.getFile = async (PATH, save) => { 713 | let res 714 | 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) 715 | //if (!Buffer.isBuffer(data)) throw new TypeError('Result is not a buffer') 716 | let type = await FileType.fromBuffer(data) || { 717 | mime: 'application/octet-stream', 718 | ext: '.bin' 719 | } 720 | filename = path.join(__filename, '../src/' + new Date * 1 + '.' + type.ext) 721 | if (data && save) fs.promises.writeFile(filename, data) 722 | return { 723 | res, 724 | filename, 725 | size: await getSizeMedia(data), 726 | ...type, 727 | data 728 | } 729 | 730 | } 731 | 732 | return naze 733 | } 734 | 735 | startNaze() 736 | 737 | 738 | let file = require.resolve(__filename) 739 | fs.watchFile(file, () => { 740 | fs.unwatchFile(file) 741 | console.log(chalk.redBright(`Update ${__filename}`)) 742 | delete require.cache[file] 743 | require(file) 744 | }) 745 | -------------------------------------------------------------------------------- /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/cloudDBAdapter.js: -------------------------------------------------------------------------------- 1 | const got = require('got') 2 | 3 | const stringify = obj => JSON.stringify(obj, null, 2) 4 | const parse = str => JSON.parse(str, (_, v) => { 5 | if ( 6 | v !== null && 7 | typeof v === 'object' && 8 | 'type' in v && 9 | v.type === 'Buffer' && 10 | 'data' in v && 11 | Array.isArray(v.data)) { 12 | return Buffer.from(v.data) 13 | } 14 | return v 15 | }) 16 | class CloudDBAdapter { 17 | constructor(url, { 18 | serialize = stringify, 19 | deserialize = parse, 20 | fetchOptions = {} 21 | } = {}) { 22 | this.url = url 23 | this.serialize = serialize 24 | this.deserialize = deserialize 25 | this.fetchOptions = fetchOptions 26 | } 27 | 28 | async read() { 29 | try { 30 | let res = await got(this.url, { 31 | method: 'GET', 32 | headers: { 33 | 'Accept': 'application/json;q=0.9,text/plain' 34 | }, 35 | ...this.fetchOptions 36 | }) 37 | if (res.statusCode !== 200) throw res.statusMessage 38 | return this.deserialize(res.body) 39 | } catch (e) { 40 | return null 41 | } 42 | } 43 | 44 | async write(obj) { 45 | let res = await got(this.url, { 46 | method: 'POST', 47 | headers: { 48 | 'Content-Type': 'application/json' 49 | }, 50 | ...this.fetchOptions, 51 | body: this.serialize(obj) 52 | }) 53 | if (res.statusCode !== 200) throw res.statusMessage 54 | return res.body 55 | } 56 | } 57 | 58 | module.exports = CloudDBAdapter 59 | -------------------------------------------------------------------------------- /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, '../src', + 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/database.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const _fs = require('fs') 3 | const { promises: fs } = _fs 4 | 5 | class Database { 6 | /** 7 | * Create new Database 8 | * @param {String} filepath Path to specified json database 9 | * @param {...any} args JSON.stringify arguments 10 | */ 11 | constructor(filepath, ...args) { 12 | this.file = path.resolve(filepath) 13 | this.logger = console 14 | 15 | this._load() 16 | 17 | this._jsonargs = args 18 | this._state = false 19 | this._queue = [] 20 | this._interval = setInterval(async () => { 21 | if (!this._state && this._queue && this._queue[0]) { 22 | this._state = true 23 | await this[this._queue.shift()]().catch(this.logger.error) 24 | this._state = false 25 | } 26 | }, 1000) 27 | 28 | } 29 | 30 | get data() { 31 | return this._data 32 | } 33 | 34 | set data(value) { 35 | this._data = value 36 | this.save() 37 | } 38 | 39 | /** 40 | * Queue Load 41 | */ 42 | load() { 43 | this._queue.push('_load') 44 | } 45 | 46 | /** 47 | * Queue Save 48 | */ 49 | save() { 50 | this._queue.push('_save') 51 | } 52 | 53 | _load() { 54 | try { 55 | return this._data = _fs.existsSync(this.file) ? JSON.parse(_fs.readFileSync(this.file)) : {} 56 | } catch (e) { 57 | this.logger.error(e) 58 | return this._data = {} 59 | } 60 | } 61 | 62 | async _save() { 63 | let dirname = path.dirname(this.file) 64 | if (!_fs.existsSync(dirname)) await fs.mkdir(dirname, { recursive: true }) 65 | await fs.writeFile(this.file, JSON.stringify(this._data, ...this._jsonargs)) 66 | return this.file 67 | } 68 | } 69 | 70 | module.exports = Database 71 | 72 | -------------------------------------------------------------------------------- /lib/exif.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create By Mhankbarbar 3 | * Contact - 4 | * Follow https://github.com/MhankBarBar 5 | */ 6 | 7 | 8 | const fs = require('fs') 9 | const { tmpdir } = require("os") 10 | const Crypto = require("crypto") 11 | const ff = require('fluent-ffmpeg') 12 | const webp = require("node-webpmux") 13 | const path = require("path") 14 | 15 | 16 | async function imageToWebp (media) { 17 | 18 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 19 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.jpg`) 20 | 21 | fs.writeFileSync(tmpFileIn, media) 22 | 23 | await new Promise((resolve, reject) => { 24 | ff(tmpFileIn) 25 | .on("error", reject) 26 | .on("end", () => resolve(true)) 27 | .addOutputOptions([ 28 | "-vcodec", 29 | "libwebp", 30 | "-vf", 31 | "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" 32 | ]) 33 | .toFormat("webp") 34 | .save(tmpFileOut) 35 | }) 36 | 37 | const buff = fs.readFileSync(tmpFileOut) 38 | fs.unlinkSync(tmpFileOut) 39 | fs.unlinkSync(tmpFileIn) 40 | return buff 41 | } 42 | 43 | async function videoToWebp (media) { 44 | 45 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 46 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.mp4`) 47 | 48 | fs.writeFileSync(tmpFileIn, media) 49 | 50 | await new Promise((resolve, reject) => { 51 | ff(tmpFileIn) 52 | .on("error", reject) 53 | .on("end", () => resolve(true)) 54 | .addOutputOptions([ 55 | "-vcodec", 56 | "libwebp", 57 | "-vf", 58 | "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", 59 | "-loop", 60 | "0", 61 | "-ss", 62 | "00:00:00", 63 | "-t", 64 | "00:00:05", 65 | "-preset", 66 | "default", 67 | "-an", 68 | "-vsync", 69 | "0" 70 | ]) 71 | .toFormat("webp") 72 | .save(tmpFileOut) 73 | }) 74 | 75 | const buff = fs.readFileSync(tmpFileOut) 76 | fs.unlinkSync(tmpFileOut) 77 | fs.unlinkSync(tmpFileIn) 78 | return buff 79 | } 80 | 81 | async function writeExifImg (media, metadata) { 82 | let wMedia = await imageToWebp(media) 83 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 84 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 85 | fs.writeFileSync(tmpFileIn, wMedia) 86 | 87 | if (metadata.packname || metadata.author) { 88 | const img = new webp.Image() 89 | const json = { "sticker-pack-id": `https://github.com/nazedev/naze`, "sticker-pack-name": metadata.packname, "sticker-pack-publisher": metadata.author, "emojis": metadata.categories ? metadata.categories : [""] } 90 | 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]) 91 | const jsonBuff = Buffer.from(JSON.stringify(json), "utf-8") 92 | const exif = Buffer.concat([exifAttr, jsonBuff]) 93 | exif.writeUIntLE(jsonBuff.length, 14, 4) 94 | await img.load(tmpFileIn) 95 | fs.unlinkSync(tmpFileIn) 96 | img.exif = exif 97 | await img.save(tmpFileOut) 98 | return tmpFileOut 99 | } 100 | } 101 | 102 | async function writeExifVid (media, metadata) { 103 | let wMedia = await videoToWebp(media) 104 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 105 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 106 | fs.writeFileSync(tmpFileIn, wMedia) 107 | 108 | if (metadata.packname || metadata.author) { 109 | const img = new webp.Image() 110 | const json = { "sticker-pack-id": `https://github.com/nazedev/naze`, "sticker-pack-name": metadata.packname, "sticker-pack-publisher": metadata.author, "emojis": metadata.categories ? metadata.categories : [""] } 111 | 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]) 112 | const jsonBuff = Buffer.from(JSON.stringify(json), "utf-8") 113 | const exif = Buffer.concat([exifAttr, jsonBuff]) 114 | exif.writeUIntLE(jsonBuff.length, 14, 4) 115 | await img.load(tmpFileIn) 116 | fs.unlinkSync(tmpFileIn) 117 | img.exif = exif 118 | await img.save(tmpFileOut) 119 | return tmpFileOut 120 | } 121 | } 122 | 123 | async function writeExif (media, metadata) { 124 | let wMedia = /webp/.test(media.mimetype) ? media.data : /image/.test(media.mimetype) ? await imageToWebp(media.data) : /video/.test(media.mimetype) ? await videoToWebp(media.data) : "" 125 | const tmpFileIn = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 126 | const tmpFileOut = path.join(tmpdir(), `${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`) 127 | fs.writeFileSync(tmpFileIn, wMedia) 128 | 129 | if (metadata.packname || metadata.author) { 130 | const img = new webp.Image() 131 | const json = { "sticker-pack-id": `https://github.com/nazedev/naze`, "sticker-pack-name": metadata.packname, "sticker-pack-publisher": metadata.author, "emojis": metadata.categories ? metadata.categories : [""] } 132 | 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]) 133 | const jsonBuff = Buffer.from(JSON.stringify(json), "utf-8") 134 | const exif = Buffer.concat([exifAttr, jsonBuff]) 135 | exif.writeUIntLE(jsonBuff.length, 14, 4) 136 | await img.load(tmpFileIn) 137 | fs.unlinkSync(tmpFileIn) 138 | img.exif = exif 139 | await img.save(tmpFileOut) 140 | return tmpFileOut 141 | } 142 | } 143 | 144 | module.exports = { imageToWebp, videoToWebp, writeExifImg, writeExifVid, writeExif } 145 | -------------------------------------------------------------------------------- /lib/jadibot.js: -------------------------------------------------------------------------------- 1 | 2 | let { WAConnection, MessageType, Mimetype} = require('@adiwajshing/baileys') 3 | let qrcode = require('qrcode') 4 | const fs = require('fs') 5 | 6 | listjadibot = []; 7 | 8 | const jadibot = async(reply,naze,id) => { 9 | conn = new WAConnection() 10 | conn.logger.level = 'warn' 11 | conn.version = [2, 2143, 3] 12 | conn.browserDescription = [ 'Numpang', '', '3.5' ] 13 | conn.on('qr', async qr => { 14 | let bot = await qrcode.toDataURL(qr, { scale: 8 }) 15 | let buffer = new Buffer.from(bot.replace('data:image/png;base64,', ''), 'base64') 16 | bot = await naze.sendMessage(id,buffer,MessageType.image,{caption:'Scan QR Untuk menjadi bot\n*Rules:*\nQR akan diganti setiap 30 detik'}) 17 | setTimeout(() => { 18 | naze.deleteMessage(id, bot.key) 19 | },30000) 20 | }) 21 | conn.on('connecting', () => { 22 | }) 23 | conn.on('open', () => { 24 | reply(`Sukses Jadi BOT\n\n*Device*:\n\n ${JSON.stringify(conn.user,null,2)}`) 25 | }) 26 | await conn.connect({timeoutMs: 30 * 1000}) 27 | listjadibot.push(conn.user) 28 | conn.on('chat-update', async (message) => { 29 | require('../naze.js')(conn, message) 30 | }) 31 | } 32 | 33 | const stopjadibot = (reply) => { 34 | conn = new WAConnection(); 35 | conn.close() 36 | reply('Sukses stop jadibot') 37 | } 38 | 39 | module.exports = { 40 | jadibot, 41 | stopjadibot, 42 | listjadibot 43 | } -------------------------------------------------------------------------------- /lib/jadwaltv.js: -------------------------------------------------------------------------------- 1 | //════════════════════════════// 2 | //If you want to recode, reupload 3 | //or copy the codes/script, 4 | //pls give credit 5 | //no credit? i will take action immediately 6 | //© 2022 Xeon Bot Inc. Cheems Bot MD 7 | //Thank you to Lord Buddha, Family and Myself 8 | //════════════════════════════// 9 | //recode kar ke youtube pe upload kar rhe ya 10 | //codes copy kar ke apne script me dal rhe 11 | //hai to, description me xeon ka yt channel 12 | // ka link paste kr dena as a cradit or github 13 | //repo me bhi tag kardena baki jo 14 | //bhi karna hai apki marzi, thank you!🦄 15 | //════════════════════════════// 16 | //If you recode and uploading on your channel 17 | //or copy pasting the codes in ur script, 18 | //i give permission to do as long as you 19 | //put Xeons youtube channel link in the video 20 | //description and tag me on githuh repo, 21 | //thank you🦄 22 | //════════════════════════════// 23 | 24 | const {default: Axios} = require('axios') 25 | const cheerio = require('cheerio') 26 | 27 | function jadwaltv(query) { 28 | return new Promise(async (resolve, reject) => { 29 | const channelna = query; 30 | let stasiun = [ 31 | "rcti", 32 | "nettv", 33 | "antv", 34 | "gtv", 35 | "indosiar", 36 | "inewstv", 37 | "kompastv", 38 | "metrotv", 39 | "mnctv", 40 | "rtv", 41 | "sctv", 42 | "trans7", 43 | "transtv", 44 | "tvone", 45 | "tvri", 46 | ]; 47 | let isist = `*Available channels* :\n\n`; 48 | for (let i = 0;i < stasiun.length;i++) { 49 | isist += `*➣* ${stasiun[i]}\n`; 50 | } 51 | try { 52 | // const tv_switch = stasiun[0] 53 | Axios.get("https://www.jadwaltv.net/channel/" + channelna) 54 | .then(({ 55 | data 56 | }) => { 57 | const $ = cheerio.load(data); 58 | let isitable1 = []; 59 | let isitable2 = []; 60 | $("div > div > table:nth-child(3) > tbody > tr").each(function ( 61 | i, 62 | result 63 | ) { 64 | isitable1.push({ 65 | jam: result.children[0].children[0].data, 66 | tayang: result.children[1].children[0].data, 67 | }); 68 | }); 69 | // console.log(isitable1) 70 | $("div > div > table:nth-child(5) > tbody > tr").each(function ( 71 | i, 72 | result 73 | ) { 74 | isitable2.push({ 75 | jam: result.children[0].children[0].data, 76 | tayang: result.children[1].children[0].data, 77 | }); 78 | }); 79 | const semuatable = []; 80 | 81 | for (let i = 0;i < isitable1.length;i++) { 82 | semuatable.push(isitable1[i]); 83 | } 84 | for (let i = 0;i < isitable2.length;i++) { 85 | semuatable.push(isitable2[i]); 86 | } 87 | // console.log(semuatable) 88 | let daftartay = `*Menampilkan daftar tayang channel ${channelna}*\n\n`; 89 | for (let i = 0;i < semuatable.length;i++) { 90 | daftartay += `${semuatable[i].jam} ${semuatable[i].tayang}\n`; 91 | } 92 | resolve(daftartay); 93 | // console.log(semuatable) 94 | }) 95 | .catch((e) => { 96 | resolve(isist); 97 | // console.log(e) 98 | }); 99 | } catch (e) { 100 | resolve(isist); 101 | console.log(e); 102 | } 103 | }) 104 | } 105 | 106 | module.exports = {jadwaltv} -------------------------------------------------------------------------------- /lib/lowdb/CAF: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/lowdb/Low.d.ts: -------------------------------------------------------------------------------- 1 | export interface Adapter { 2 | read: () => Promise; 3 | write: (data: T) => Promise; 4 | } 5 | export declare class Low { 6 | adapter: Adapter; 7 | data: T | null; 8 | constructor(adapter: Adapter); 9 | read(): Promise; 10 | write(): Promise; 11 | } 12 | -------------------------------------------------------------------------------- /lib/lowdb/Low.js: -------------------------------------------------------------------------------- 1 | const { MissingAdapterError } = require('./MissingAdapterError.js'); 2 | class Low { 3 | constructor(adapter) { 4 | this.data = null; 5 | if (adapter) { 6 | this.adapter = adapter; 7 | } 8 | else { 9 | throw new MissingAdapterError(); 10 | } 11 | } 12 | async read() { 13 | this.data = await this.adapter.read(); 14 | } 15 | async write() { 16 | if (this.data) { 17 | await this.adapter.write(this.data); 18 | } 19 | } 20 | } 21 | module.exports = { Low }; 22 | -------------------------------------------------------------------------------- /lib/lowdb/LowSync.d.ts: -------------------------------------------------------------------------------- 1 | export interface SyncAdapter { 2 | read: () => T | null; 3 | write: (data: T) => void; 4 | } 5 | export declare class LowSync { 6 | adapter: SyncAdapter; 7 | data: T | null; 8 | constructor(adapter: SyncAdapter); 9 | read(): void; 10 | write(): void; 11 | } 12 | -------------------------------------------------------------------------------- /lib/lowdb/LowSync.js: -------------------------------------------------------------------------------- 1 | const { MissingAdapterError } = require('./MissingAdapterError.js'); 2 | class LowSync { 3 | constructor(adapter) { 4 | this.data = null; 5 | if (adapter) { 6 | this.adapter = adapter; 7 | } 8 | else { 9 | throw new MissingAdapterError(); 10 | } 11 | } 12 | read() { 13 | this.data = this.adapter.read(); 14 | } 15 | write() { 16 | if (this.data !== null) { 17 | this.adapter.write(this.data); 18 | } 19 | } 20 | } 21 | module.exports = { LowSync }; 22 | -------------------------------------------------------------------------------- /lib/lowdb/MissingAdapterError.d.ts: -------------------------------------------------------------------------------- 1 | export declare class MissingAdapterError extends Error { 2 | constructor(); 3 | } 4 | -------------------------------------------------------------------------------- /lib/lowdb/MissingAdapterError.js: -------------------------------------------------------------------------------- 1 | class MissingAdapterError extends Error { 2 | constructor() { 3 | super(); 4 | this.message = 'Missing Adapter'; 5 | } 6 | } 7 | module.exports = { MissingAdapterError }; 8 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/CAF: -------------------------------------------------------------------------------- 1 | >\\\< 2 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/JSONFile.d.ts: -------------------------------------------------------------------------------- 1 | import { Adapter } from '../Low.js'; 2 | export declare class JSONFile implements Adapter { 3 | private adapter; 4 | constructor(filename: string); 5 | read(): Promise; 6 | write(obj: T): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/JSONFile.js: -------------------------------------------------------------------------------- 1 | const { TextFile } = require('./TextFile.js'); 2 | class JSONFile { 3 | constructor(filename) { 4 | this.adapter = new TextFile(filename); 5 | } 6 | async read() { 7 | const data = await this.adapter.read(); 8 | if (data === null) { 9 | return null; 10 | } 11 | else { 12 | return JSON.parse(data); 13 | } 14 | } 15 | write(obj) { 16 | return this.adapter.write(JSON.stringify(obj, null, 2)); 17 | } 18 | } 19 | module.exports = { JSONFile }; 20 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/JSONFileSync.d.ts: -------------------------------------------------------------------------------- 1 | import { SyncAdapter } from '../LowSync.js'; 2 | export declare class JSONFileSync implements SyncAdapter { 3 | private adapter; 4 | constructor(filename: string); 5 | read(): T | null; 6 | write(obj: T): void; 7 | } 8 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/JSONFileSync.js: -------------------------------------------------------------------------------- 1 | const { TextFileSync } = require('./TextFileSync.js'); 2 | class JSONFileSync { 3 | constructor(filename) { 4 | this.adapter = new TextFileSync(filename); 5 | } 6 | read() { 7 | const data = this.adapter.read(); 8 | if (data === null) { 9 | return null; 10 | } 11 | else { 12 | return JSON.parse(data); 13 | } 14 | } 15 | write(obj) { 16 | this.adapter.write(JSON.stringify(obj, null, 2)); 17 | } 18 | } 19 | module.exports = { JSONFileSync }; 20 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/LocalStorage.d.ts: -------------------------------------------------------------------------------- 1 | import { SyncAdapter } from '../LowSync.js'; 2 | export declare class LocalStorage implements SyncAdapter { 3 | private key; 4 | constructor(key: string); 5 | read(): T | null; 6 | write(obj: T): void; 7 | } 8 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/LocalStorage.js: -------------------------------------------------------------------------------- 1 | class LocalStorage { 2 | constructor(key) { 3 | this.key = key; 4 | } 5 | read() { 6 | const value = localStorage.getItem(this.key); 7 | if (value === null) { 8 | return null; 9 | } 10 | return JSON.parse(value); 11 | } 12 | write(obj) { 13 | localStorage.setItem(this.key, JSON.stringify(obj)); 14 | } 15 | } 16 | module.exports = { LocalStorage }; 17 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/Memory.d.ts: -------------------------------------------------------------------------------- 1 | import { Adapter } from '../Low.js'; 2 | export declare class Memory implements Adapter { 3 | private data; 4 | read(): Promise; 5 | write(obj: T): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/Memory.js: -------------------------------------------------------------------------------- 1 | class Memory { 2 | constructor() { 3 | this.data = null; 4 | } 5 | read() { 6 | return Promise.resolve(this.data); 7 | } 8 | write(obj) { 9 | this.data = obj; 10 | return Promise.resolve(); 11 | } 12 | } 13 | module.exports = { Memory }; 14 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/MemorySync.d.ts: -------------------------------------------------------------------------------- 1 | import { SyncAdapter } from '../LowSync.js'; 2 | export declare class MemorySync implements SyncAdapter { 3 | private data; 4 | read(): T | null; 5 | write(obj: T): void; 6 | } 7 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/MemorySync.js: -------------------------------------------------------------------------------- 1 | class MemorySync { 2 | constructor() { 3 | this.data = null; 4 | } 5 | read() { 6 | return this.data || null; 7 | } 8 | write(obj) { 9 | this.data = obj; 10 | } 11 | } 12 | module.exports = { MemorySync }; 13 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/TextFile.d.ts: -------------------------------------------------------------------------------- 1 | import { Adapter } from '../Low.js'; 2 | export declare class TextFile implements Adapter { 3 | private filename; 4 | private writer; 5 | constructor(filename: string); 6 | read(): Promise; 7 | write(str: string): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/TextFile.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { Writer } = require('steno'); 3 | class TextFile { 4 | constructor(filename) { 5 | this.filename = filename; 6 | this.writer = new Writer(filename); 7 | } 8 | async read() { 9 | let data; 10 | try { 11 | data = await fs.promises.readFile(this.filename, 'utf-8'); 12 | } 13 | catch (e) { 14 | if (e.code === 'ENOENT') { 15 | return null; 16 | } 17 | throw e; 18 | } 19 | return data; 20 | } 21 | write(str) { 22 | return this.writer.write(str); 23 | } 24 | } 25 | module.exports = { TextFile }; -------------------------------------------------------------------------------- /lib/lowdb/adapters/TextFileSync.d.ts: -------------------------------------------------------------------------------- 1 | import { SyncAdapter } from '../LowSync.js'; 2 | export declare class TextFileSync implements SyncAdapter { 3 | private tempFilename; 4 | private filename; 5 | constructor(filename: string); 6 | read(): string | null; 7 | write(str: string): void; 8 | } 9 | -------------------------------------------------------------------------------- /lib/lowdb/adapters/TextFileSync.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | class TextFileSync { 4 | constructor(filename) { 5 | this.filename = filename; 6 | this.tempFilename = path.join(path.dirname(filename), `.${path.basename(filename)}.tmp`); 7 | } 8 | read() { 9 | let data; 10 | try { 11 | data = fs.readFileSync(this.filename, 'utf-8'); 12 | } 13 | catch (e) { 14 | if (e.code === 'ENOENT') { 15 | return null; 16 | } 17 | throw e; 18 | } 19 | return data; 20 | } 21 | write(str) { 22 | fs.writeFileSync(this.tempFilename, str); 23 | fs.renameSync(this.tempFilename, this.filename); 24 | } 25 | } 26 | module.exports = { TextFileSync }; 27 | -------------------------------------------------------------------------------- /lib/lowdb/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './adapters/JSONFile.js'; 2 | export * from './adapters/JSONFileSync.js'; 3 | export * from './adapters/LocalStorage.js'; 4 | export * from './adapters/Memory.js'; 5 | export * from './adapters/MemorySync.js'; 6 | export * from './adapters/TextFile.js'; 7 | export * from './adapters/TextFileSync.js'; 8 | export * from './Low.js'; 9 | export * from './LowSync.js'; 10 | -------------------------------------------------------------------------------- /lib/lowdb/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('./adapters/JSONFile.js'), 3 | ...require('./adapters/JSONFileSync.js'), 4 | ...require('./adapters/LocalStorage.js'), 5 | ...require('./adapters/Memory.js'), 6 | ...require('./adapters/MemorySync.js'), 7 | ...require('./adapters/TextFile.js'), 8 | ...require('./adapters/TextFileSync.js'), 9 | ...require('./Low.js'), 10 | ...require('./LowSync.js'), 11 | } -------------------------------------------------------------------------------- /lib/mediafire.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | const cheerio = require('cheerio') 3 | 4 | const mediafireDl = async (url) => { 5 | const res = await axios.get(url) 6 | const $ = cheerio.load(res.data) 7 | const hasil = [] 8 | const link = $('a#downloadButton').attr('href') 9 | const size = $('a#downloadButton').text().replace('Download', '').replace('(', '').replace(')', '').replace('\n', '').replace('\n', '').replace(' ', '') 10 | const seplit = link.split('/') 11 | const nama = seplit[5] 12 | mime = nama.split('.') 13 | mime = mime[1] 14 | hasil.push({ nama, mime, size, link }) 15 | return hasil 16 | } 17 | 18 | 19 | module.exports = { mediafireDl } -------------------------------------------------------------------------------- /lib/mongoDB.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const { Schema } = mongoose 3 | 4 | module.exports = class mongoDB { 5 | constructor(url, options = { useNewUrlParser: true, useUnifiedTopology: true }) { 6 | this.url = url 7 | this.data = this._data = this._schema = this._model = {} 8 | this.db 9 | this.options = options 10 | } 11 | async read() { 12 | this.db = await mongoose.connect(this.url, { ...this.options }) 13 | this.connection = mongoose.connection 14 | let schema = this._schema = new Schema({ 15 | data: { 16 | type: Object, 17 | required: true, //depends on whether the field is mandatory or not 18 | default: {} 19 | } 20 | }) 21 | // this._model = mongoose.model('data', schema) 22 | try { this._model = mongoose.model('data', schema) } catch { this._model = mongoose.model('data') } 23 | this._data = await this._model.findOne({}) 24 | if (!this._data) { 25 | this.data = {} 26 | await this.write(this.data) 27 | this._data = await this._model.findOne({}) 28 | } else this.data = this._data.data 29 | return this.data 30 | } 31 | 32 | 33 | async write(data) { 34 | if (!data) return data 35 | if (!this._data) return (new this._model({ data })).save() 36 | this._model.findById(this._data._id, (err, docs) => { 37 | if (!err) { 38 | if (!docs.data) docs.data = {} 39 | docs.data = data 40 | return docs.save() 41 | } 42 | }) 43 | } 44 | } -------------------------------------------------------------------------------- /lib/myfunc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create By Dika Ardnt. 3 | * Recode By Naze Dev 4 | * Contact Me on wa.me/6282113821188 5 | * Follow https://github.com/nazedev 6 | */ 7 | 8 | const { proto, delay, getContentType } = require('@adiwajshing/baileys') 9 | const chalk = require('chalk') 10 | const fs = require('fs') 11 | const Crypto = require('crypto') 12 | const axios = require('axios') 13 | const moment = require('moment-timezone') 14 | const { sizeFormatter } = require('human-readable') 15 | const util = require('util') 16 | const Jimp = require('jimp') 17 | const { defaultMaxListeners } = require('stream') 18 | 19 | 20 | const unixTimestampSeconds = (date = new Date()) => Math.floor(date.getTime() / 1000) 21 | 22 | exports.unixTimestampSeconds = unixTimestampSeconds 23 | 24 | exports.generateMessageTag = (epoch) => { 25 | let tag = (0, exports.unixTimestampSeconds)().toString(); 26 | if (epoch) 27 | tag += '.--' + epoch; // attach epoch if provided 28 | return tag; 29 | } 30 | 31 | exports.processTime = (timestamp, now) => { 32 | return moment.duration(now - moment(timestamp * 1000)).asSeconds() 33 | } 34 | 35 | exports.getRandom = (ext) => { 36 | return `${Math.floor(Math.random() * 10000)}${ext}` 37 | } 38 | 39 | exports.getBuffer = async (url, options) => { 40 | try { 41 | options ? options : {} 42 | const res = await axios({ 43 | method: "get", 44 | url, 45 | headers: { 46 | 'DNT': 1, 47 | 'Upgrade-Insecure-Request': 1 48 | }, 49 | ...options, 50 | responseType: 'arraybuffer' 51 | }) 52 | return res.data 53 | } catch (err) { 54 | return err 55 | } 56 | } 57 | 58 | exports.fetchJson = async (url, options) => { 59 | try { 60 | options ? options : {} 61 | const res = await axios({ 62 | method: 'GET', 63 | url: url, 64 | headers: { 65 | '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' 66 | }, 67 | ...options 68 | }) 69 | return res.data 70 | } catch (err) { 71 | return err 72 | } 73 | } 74 | 75 | exports.runtime = function(seconds) { 76 | seconds = Number(seconds); 77 | var d = Math.floor(seconds / (3600 * 24)); 78 | var h = Math.floor(seconds % (3600 * 24) / 3600); 79 | var m = Math.floor(seconds % 3600 / 60); 80 | var s = Math.floor(seconds % 60); 81 | var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : ""; 82 | var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : ""; 83 | var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : ""; 84 | var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : ""; 85 | return dDisplay + hDisplay + mDisplay + sDisplay; 86 | } 87 | 88 | exports.clockString = (ms) => { 89 | let h = isNaN(ms) ? '--' : Math.floor(ms / 3600000) 90 | let m = isNaN(ms) ? '--' : Math.floor(ms / 60000) % 60 91 | let s = isNaN(ms) ? '--' : Math.floor(ms / 1000) % 60 92 | return [h, m, s].map(v => v.toString().padStart(2, 0)).join(':') 93 | } 94 | 95 | exports.sleep = async (ms) => { 96 | return new Promise(resolve => setTimeout(resolve, ms)); 97 | } 98 | 99 | exports.isUrl = (url) => { 100 | 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')) 101 | } 102 | 103 | exports.getTime = (format, date) => { 104 | if (date) { 105 | return moment(date).locale('id').format(format) 106 | } else { 107 | return moment.tz('Asia/Jakarta').locale('id').format(format) 108 | } 109 | } 110 | 111 | exports.formatDate = (n, locale = 'id') => { 112 | let d = new Date(n) 113 | return d.toLocaleDateString(locale, { 114 | weekday: 'long', 115 | day: 'numeric', 116 | month: 'long', 117 | year: 'numeric', 118 | hour: 'numeric', 119 | minute: 'numeric', 120 | second: 'numeric' 121 | }) 122 | } 123 | 124 | exports.tanggal = (numer) => { 125 | myMonths = ["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","November","Desember"]; 126 | myDays = ['Minggu','Senin','Selasa','Rabu','Kamis','Jum’at','Sabtu']; 127 | var tgl = new Date(numer); 128 | var day = tgl.getDate() 129 | bulan = tgl.getMonth() 130 | var thisDay = tgl.getDay(), 131 | thisDay = myDays[thisDay]; 132 | var yy = tgl.getYear() 133 | var year = (yy < 1000) ? yy + 1900 : yy; 134 | const time = moment.tz('Asia/Jakarta').format('DD/MM HH:mm:ss') 135 | let d = new Date 136 | let locale = 'id' 137 | let gmt = new Date(0).getTime() - new Date('1 January 1970').getTime() 138 | let weton = ['Pahing', 'Pon','Wage','Kliwon','Legi'][Math.floor(((d * 1) + gmt) / 84600000) % 5] 139 | 140 | return`${thisDay}, ${day} - ${myMonths[bulan]} - ${year}` 141 | } 142 | 143 | exports.formatp = sizeFormatter({ 144 | std: 'JEDEC', //'SI' = default | 'IEC' | 'JEDEC' 145 | decimalPlaces: 2, 146 | keepTrailingZeroes: false, 147 | render: (literal, symbol) => `${literal} ${symbol}B`, 148 | }) 149 | 150 | exports.jsonformat = (string) => { 151 | return JSON.stringify(string, null, 2) 152 | } 153 | 154 | function format(...args) { 155 | return util.format(...args) 156 | } 157 | 158 | exports.logic = (check, inp, out) => { 159 | if (inp.length !== out.length) throw new Error('Input and Output must have same length') 160 | for (let i in inp) 161 | if (util.isDeepStrictEqual(check, inp[i])) return out[i] 162 | return null 163 | } 164 | 165 | exports.generateProfilePicture = async (buffer) => { 166 | const jimp = await Jimp.read(buffer) 167 | const min = jimp.getWidth() 168 | const max = jimp.getHeight() 169 | const cropped = jimp.crop(0, 0, min, max) 170 | return { 171 | img: await cropped.scaleToFit(720, 720).getBufferAsync(Jimp.MIME_JPEG), 172 | preview: await cropped.scaleToFit(720, 720).getBufferAsync(Jimp.MIME_JPEG) 173 | } 174 | } 175 | 176 | exports.bytesToSize = (bytes, decimals = 2) => { 177 | if (bytes === 0) return '0 Bytes'; 178 | 179 | const k = 1024; 180 | const dm = decimals < 0 ? 0 : decimals; 181 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; 182 | 183 | const i = Math.floor(Math.log(bytes) / Math.log(k)); 184 | 185 | return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; 186 | } 187 | 188 | exports.getSizeMedia = (path) => { 189 | return new Promise((resolve, reject) => { 190 | if (/http/.test(path)) { 191 | axios.get(path) 192 | .then((res) => { 193 | let length = parseInt(res.headers['content-length']) 194 | let size = exports.bytesToSize(length, 3) 195 | if(!isNaN(length)) resolve(size) 196 | }) 197 | } else if (Buffer.isBuffer(path)) { 198 | let length = Buffer.byteLength(path) 199 | let size = exports.bytesToSize(length, 3) 200 | if(!isNaN(length)) resolve(size) 201 | } else { 202 | reject('error gatau apah') 203 | } 204 | }) 205 | } 206 | 207 | exports.parseMention = (text = '') => { 208 | return [...text.matchAll(/@([0-9]{5,16}|0)/g)].map(v => v[1] + '@s.whatsapp.net') 209 | } 210 | 211 | exports.getGroupAdmins = (participants) => { 212 | let admins = [] 213 | for (let i of participants) { 214 | i.admin === "superadmin" ? admins.push(i.id) : i.admin === "admin" ? admins.push(i.id) : '' 215 | } 216 | return admins || [] 217 | } 218 | 219 | /** 220 | * Serialize Message 221 | * @param {WAConnection} conn 222 | * @param {Object} m 223 | * @param {store} store 224 | */ 225 | exports.smsg = (conn, m, store) => { 226 | if (!m) return m 227 | let M = proto.WebMessageInfo 228 | if (m.key) { 229 | m.id = m.key.id 230 | m.isBaileys = m.id.startsWith('BAE5') && m.id.length === 16 231 | m.chat = m.key.remoteJid 232 | m.fromMe = m.key.fromMe 233 | m.isGroup = m.chat.endsWith('@g.us') 234 | m.sender = conn.decodeJid(m.fromMe && conn.user.id || m.participant || m.key.participant || m.chat || '') 235 | if (m.isGroup) m.participant = conn.decodeJid(m.key.participant) || '' 236 | } 237 | if (m.message) { 238 | m.mtype = getContentType(m.message) 239 | m.msg = (m.mtype == 'viewOnceMessage' ? m.message[m.mtype].message[getContentType(m.message[m.mtype].message)] : m.message[m.mtype]) 240 | m.body = m.message.conversation || m.msg.caption || m.msg.text || (m.mtype == 'listResponseMessage') && m.msg.singleSelectReply.selectedRowId || (m.mtype == 'buttonsResponseMessage') && m.msg.selectedButtonId || (m.mtype == 'viewOnceMessage') && m.msg.caption || m.text 241 | let quoted = m.quoted = m.msg.contextInfo ? m.msg.contextInfo.quotedMessage : null 242 | m.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] 243 | if (m.quoted) { 244 | let type = getContentType(quoted) 245 | m.quoted = m.quoted[type] 246 | if (['productMessage'].includes(type)) { 247 | type = getContentType(m.quoted) 248 | m.quoted = m.quoted[type] 249 | } 250 | if (typeof m.quoted === 'string') m.quoted = { 251 | text: m.quoted 252 | } 253 | m.quoted.mtype = type 254 | m.quoted.id = m.msg.contextInfo.stanzaId 255 | m.quoted.chat = m.msg.contextInfo.remoteJid || m.chat 256 | m.quoted.isBaileys = m.quoted.id ? m.quoted.id.startsWith('BAE5') && m.quoted.id.length === 16 : false 257 | m.quoted.sender = conn.decodeJid(m.msg.contextInfo.participant) 258 | m.quoted.fromMe = m.quoted.sender === (conn.user && conn.user.id) 259 | m.quoted.text = m.quoted.text || m.quoted.caption || m.quoted.conversation || m.quoted.contentText || m.quoted.selectedDisplayText || m.quoted.title || '' 260 | m.quoted.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] 261 | m.getQuotedObj = m.getQuotedMessage = async () => { 262 | if (!m.quoted.id) return false 263 | let q = await store.loadMessage(m.chat, m.quoted.id, conn) 264 | return exports.smsg(conn, q, store) 265 | } 266 | let vM = m.quoted.fakeObj = M.fromObject({ 267 | key: { 268 | remoteJid: m.quoted.chat, 269 | fromMe: m.quoted.fromMe, 270 | id: m.quoted.id 271 | }, 272 | message: quoted, 273 | ...(m.isGroup ? { participant: m.quoted.sender } : {}) 274 | }) 275 | 276 | /** 277 | * 278 | * @returns 279 | */ 280 | m.quoted.delete = () => conn.sendMessage(m.quoted.chat, { delete: vM.key }) 281 | 282 | /** 283 | * 284 | * @param {*} jid 285 | * @param {*} forceForward 286 | * @param {*} options 287 | * @returns 288 | */ 289 | m.quoted.copyNForward = (jid, forceForward = false, options = {}) => conn.copyNForward(jid, vM, forceForward, options) 290 | 291 | /** 292 | * 293 | * @returns 294 | */ 295 | m.quoted.download = () => conn.downloadMediaMessage(m.quoted) 296 | } 297 | } 298 | if (m.msg.url) m.download = () => conn.downloadMediaMessage(m.msg) 299 | m.text = m.msg.text || m.msg.caption || m.message.conversation || m.msg.contentText || m.msg.selectedDisplayText || m.msg.title || '' 300 | /** 301 | * Reply to this message 302 | * @param {String|Object} text 303 | * @param {String|false} chatId 304 | * @param {Object} options 305 | */ 306 | m.reply = (text, chatId = m.chat, options = {}) => Buffer.isBuffer(text) ? conn.sendMedia(chatId, text, 'file', '', m, { ...options }) : conn.sendText(chatId, text, m, { ...options }) 307 | /** 308 | * Copy this message 309 | */ 310 | m.copy = () => exports.smsg(conn, M.fromObject(M.toObject(m))) 311 | 312 | /** 313 | * 314 | * @param {*} jid 315 | * @param {*} forceForward 316 | * @param {*} options 317 | * @returns 318 | */ 319 | m.copyNForward = (jid = m.chat, forceForward = false, options = {}) => conn.copyNForward(jid, m, forceForward, options) 320 | 321 | return m 322 | } 323 | 324 | 325 | let file = require.resolve(__filename) 326 | fs.watchFile(file, () => { 327 | fs.unwatchFile(file) 328 | console.log(chalk.redBright(`Update ${__filename}`)) 329 | delete require.cache[file] 330 | require(file) 331 | }) 332 | -------------------------------------------------------------------------------- /lib/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 = premium.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 = (naze, msg, _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 ? naze.sendMessage(idny, { text: "Premium anda sudah habis silahkan untuk membeli lagi." }) : ""; 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 | }; -------------------------------------------------------------------------------- /lib/scraper.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | const cheerio = require('cheerio') 3 | 4 | function pinterest(querry){ 5 | return new Promise(async(resolve,reject) => { 6 | axios.get('https://id.pinterest.com/search/pins/?autologin=true&q=' + querry, { 7 | headers: { 8 | "cookie" : "_auth=1; _b=\"AVna7S1p7l1C5I9u0+nR3YzijpvXOPc6d09SyCzO+DcwpersQH36SmGiYfymBKhZcGg=\"; _pinterest_sess=TWc9PSZHamJOZ0JobUFiSEpSN3Z4a2NsMk9wZ3gxL1NSc2k2NkFLaUw5bVY5cXR5alZHR0gxY2h2MVZDZlNQalNpUUJFRVR5L3NlYy9JZkthekp3bHo5bXFuaFZzVHJFMnkrR3lTbm56U3YvQXBBTW96VUgzVUhuK1Z4VURGKzczUi9hNHdDeTJ5Y2pBTmxhc2owZ2hkSGlDemtUSnYvVXh5dDNkaDN3TjZCTk8ycTdHRHVsOFg2b2NQWCtpOWxqeDNjNkk3cS85MkhhSklSb0hwTnZvZVFyZmJEUllwbG9UVnpCYVNTRzZxOXNJcmduOVc4aURtM3NtRFo3STlmWjJvSjlWTU5ITzg0VUg1NGhOTEZzME9SNFNhVWJRWjRJK3pGMFA4Q3UvcHBnWHdaYXZpa2FUNkx6Z3RNQjEzTFJEOHZoaHRvazc1c1UrYlRuUmdKcDg3ZEY4cjNtZlBLRTRBZjNYK0lPTXZJTzQ5dU8ybDdVS015bWJKT0tjTWYyRlBzclpiamdsNmtpeUZnRjlwVGJXUmdOMXdTUkFHRWloVjBMR0JlTE5YcmhxVHdoNzFHbDZ0YmFHZ1VLQXU1QnpkM1FqUTNMTnhYb3VKeDVGbnhNSkdkNXFSMXQybjRGL3pyZXRLR0ZTc0xHZ0JvbTJCNnAzQzE0cW1WTndIK0trY05HV1gxS09NRktadnFCSDR2YzBoWmRiUGZiWXFQNjcwWmZhaDZQRm1UbzNxc21pV1p5WDlabm1UWGQzanc1SGlrZXB1bDVDWXQvUis3elN2SVFDbm1DSVE5Z0d4YW1sa2hsSkZJb1h0MTFpck5BdDR0d0lZOW1Pa2RDVzNySWpXWmUwOUFhQmFSVUpaOFQ3WlhOQldNMkExeDIvMjZHeXdnNjdMYWdiQUhUSEFBUlhUVTdBMThRRmh1ekJMYWZ2YTJkNlg0cmFCdnU2WEpwcXlPOVZYcGNhNkZDd051S3lGZmo0eHV0ZE42NW8xRm5aRWpoQnNKNnNlSGFad1MzOHNkdWtER0xQTFN5Z3lmRERsZnZWWE5CZEJneVRlMDd2VmNPMjloK0g5eCswZUVJTS9CRkFweHc5RUh6K1JocGN6clc1JmZtL3JhRE1sc0NMTFlpMVErRGtPcllvTGdldz0=; _ir=0" 9 | } 10 | }).then(({ data }) => { 11 | const $ = cheerio.load(data) 12 | const result = []; 13 | const hasil = []; 14 | $('div > a').get().map(b => { 15 | const link = $(b).find('img').attr('src') 16 | result.push(link) 17 | }); 18 | result.forEach(v => { 19 | if(v == undefined) return 20 | hasil.push(v.replace(/236/g,'736')) 21 | }) 22 | hasil.shift(); 23 | resolve(hasil) 24 | }) 25 | }) 26 | } 27 | 28 | function wallpaper(title, page = '1') { 29 | return new Promise((resolve, reject) => { 30 | axios.get(`https://www.besthdwallpaper.com/search?CurrentPage=${page}&q=${title}`) 31 | .then(({ data }) => { 32 | let $ = cheerio.load(data) 33 | let hasil = [] 34 | $('div.grid-item').each(function (a, b) { 35 | hasil.push({ 36 | title: $(b).find('div.info > a > h3').text(), 37 | type: $(b).find('div.info > a:nth-child(2)').text(), 38 | source: 'https://www.besthdwallpaper.com/'+$(b).find('div > a:nth-child(3)').attr('href'), 39 | image: [$(b).find('picture > img').attr('data-src') || $(b).find('picture > img').attr('src'), $(b).find('picture > source:nth-child(1)').attr('srcset'), $(b).find('picture > source:nth-child(2)').attr('srcset')] 40 | }) 41 | }) 42 | resolve(hasil) 43 | }) 44 | }) 45 | } 46 | 47 | function wikimedia(title) { 48 | return new Promise((resolve, reject) => { 49 | axios.get(`https://commons.wikimedia.org/w/index.php?search=${title}&title=Special:MediaSearch&go=Go&type=image`) 50 | .then((res) => { 51 | let $ = cheerio.load(res.data) 52 | let hasil = [] 53 | $('.sdms-search-results__list-wrapper > div > a').each(function (a, b) { 54 | hasil.push({ 55 | title: $(b).find('img').attr('alt'), 56 | source: $(b).attr('href'), 57 | image: $(b).find('img').attr('data-src') || $(b).find('img').attr('src') 58 | }) 59 | }) 60 | resolve(hasil) 61 | }) 62 | }) 63 | } 64 | 65 | function porno() { 66 | return new Promise((resolve, reject) => { 67 | axios.get('https://tikporntok.com/?random=1') 68 | .then((res) => { 69 | const $ = cheerio.load(res.data) 70 | const hasil = {} 71 | hasil.title = $('article > h1').text() 72 | hasil.source = $('article > div.video-wrapper.vxplayer').attr('data-post') || 'Web Not Response' 73 | hasil.thumb = $('article > div.video-wrapper.vxplayer > div.vx_el').attr('data-poster') || 'https://4.bp.blogspot.com/-hyMqjmQQq4o/W6al-Rk4IpI/AAAAAAAADJ4/m-lVBA_GC9Q5d4BIQg8ZO3fYmQQC3LqSACLcBGAs/s1600/404_not_found.png' 74 | hasil.desc = $('article > div.intro').text() 75 | hasil.upload = $('article > div.single-pre-meta.ws.clearfix > time').text() 76 | hasil.like = $('article > div.single-pre-meta.ws.clearfix > div > span:nth-child(1) > span').text() 77 | hasil.dislike = $('article > div.single-pre-meta.ws.clearfix > div > span:nth-child(2) > span').text() 78 | hasil.favorite = $('article > div.single-pre-meta.ws.clearfix > div > span:nth-child(3) > span').text() 79 | hasil.views = $('article > div.single-pre-meta.ws.clearfix > div > span:nth-child(4) > span').text() 80 | hasil.tags = $('article > div.post-tags').text() 81 | hasil.video = $('article > div.video-wrapper.vxplayer > div.vx_el').attr('src') || $('article > div.video-wrapper.vxplayer > div.vx_el').attr('data-src') || 'https://4.bp.blogspot.com/-hyMqjmQQq4o/W6al-Rk4IpI/AAAAAAAADJ4/m-lVBA_GC9Q5d4BIQg8ZO3fYmQQC3LqSACLcBGAs/s1600/404_not_found.png' 82 | resolve(hasil) 83 | }) 84 | }) 85 | } 86 | 87 | function hentai() { 88 | return new Promise((resolve, reject) => { 89 | const page = Math.floor(Math.random() * 1153) 90 | axios.get('https://sfmcompile.club/page/'+page) 91 | .then((data) => { 92 | const $ = cheerio.load(data.data) 93 | const hasil = [] 94 | $('#primary > div > div > ul > li > article').each(function (a, b) { 95 | hasil.push({ 96 | title: $(b).find('header > h2').text(), 97 | link: $(b).find('header > h2 > a').attr('href'), 98 | category: $(b).find('header > div.entry-before-title > span > span').text().replace('in ', ''), 99 | share_count: $(b).find('header > div.entry-after-title > p > span.entry-shares').text(), 100 | views_count: $(b).find('header > div.entry-after-title > p > span.entry-views').text(), 101 | type: $(b).find('source').attr('type') || 'image/jpeg', 102 | video_1: $(b).find('source').attr('src') || $(b).find('img').attr('data-src'), 103 | video_2: $(b).find('video > a').attr('href') || '' 104 | }) 105 | }) 106 | resolve(hasil) 107 | }) 108 | }) 109 | } 110 | 111 | function quotesAnime() { 112 | return new Promise((resolve, reject) => { 113 | const page = Math.floor(Math.random() * 184) 114 | axios.get('https://otakotaku.com/quote/feed/'+page) 115 | .then(({ data }) => { 116 | const $ = cheerio.load(data) 117 | const hasil = [] 118 | $('div.kotodama-list').each(function(l, h) { 119 | hasil.push({ 120 | link: $(h).find('a').attr('href'), 121 | gambar: $(h).find('img').attr('data-src'), 122 | karakter: $(h).find('div.char-name').text().trim(), 123 | anime: $(h).find('div.anime-title').text().trim(), 124 | episode: $(h).find('div.meta').text(), 125 | up_at: $(h).find('small.meta').text(), 126 | quotes: $(h).find('div.quote').text().trim() 127 | }) 128 | }) 129 | resolve(hasil) 130 | }).catch(reject) 131 | }) 132 | } 133 | 134 | function igstalk(username){ 135 | return new Promise((resolve,reject) => { 136 | axios.get('https://www.instagram.com/'+ username +'/?__a=1',{ 137 | method: 'GET', 138 | headers: { 139 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", 140 | "cookie": "mid=XBXl1AALAAEbFoAEfNjZlMMG9dwX; ig_did=91E66A48-5AA2-445D-BFE6-84DC4456DE8F; fbm_124024574287414=base_domain=.instagram.com; ig_nrcb=1; shbid=\"12737\0544008624962\0541656157971:01f72a5102dc07af6845adf923ca70eb86e81ab95fa9dbfdaf157c9eef0e82fd1f10fe23\"; shbts=\"1624621971\0544008624962\0541656157971:01f74841fba8e77a0066b47ea891dec8fba6fdf9216c0816f9fb3532292f769828800ae2\"; fbsr_124024574287414=86D8femzH4_KFW4hd3Z6XFdowU6lG-uXsXRQDNl44VM.eyJ1c2VyX2lkIjoiMTAwMDA0Njc2MDc4Nzg5IiwiY29kZSI6IkFRQngzXzVOejdwVnBwby1LRGRUdEYxUFlzcUdDQXJjcmJfb05HaWFvYkNvOGtLN2paam50bHpvMTNOakFnTzVKOHQ5M0V3U3dvNkRtZ0RiY1l1Z3dQSTIybnExOUxLd3lpZTVfZll0bkNXZXBuM1hoYWFLX0w2R0pZaUpzaDBOTDBhb3pmTVBkRTVQRC12X3FnbUgxLXZYdGVmcHhfaFU0aUZNZVMxNHhFUk5OblJyMmxYTUpDa2RFYTdISXNCR2swdHhaaGF0NUt4UDR3cWZTamRwcVFfQ19sa1RUek5fU0taUTYtMjlzTkdnLUVWb3oxMUZWc3Q2OEx2ZnlIY0V0eFp0ZUxacXpiWmh6MzZrVl83VmFGd0FqVnVkTGFQN2VzT3ZRcmlTQ2pLUE5XbVcyNWhudzIzejJBSnVURW00YWR1cmN6a3ZLWU1icTd2SnN0SVdJV09RIiwib2F1dGhfdG9rZW4iOiJFQUFCd3pMaXhuallCQUJBZmJuQ3haQzZMd3h4MDFJV2MyZ3dsQ3k3Qmp0b05UNUY0WDY2NHBrUzRQeERNVXRsdmhWWkI3SXE0MGsyZ2hJQm55RHRPcW5iVjlPbUNiWGhyTFBaQUhBQjFzVFpBdHF6RFEzVTROUkhOU1V6MFVXWkNtTEdLcDNNWDRoazVIOURLbERHN0QwUlhZNHY4dHBCdVNNYjN4dnBTRGtQcHdYRlBXVU82VCIsImFsZ29yaXRobSI6IkhNQUMtU0hBMjU2IiwiaXNzdWVkX2F0IjoxNjI0NjIxOTgxfQ; fbsr_124024574287414=86D8femzH4_KFW4hd3Z6XFdowU6lG-uXsXRQDNl44VM.eyJ1c2VyX2lkIjoiMTAwMDA0Njc2MDc4Nzg5IiwiY29kZSI6IkFRQngzXzVOejdwVnBwby1LRGRUdEYxUFlzcUdDQXJjcmJfb05HaWFvYkNvOGtLN2paam50bHpvMTNOakFnTzVKOHQ5M0V3U3dvNkRtZ0RiY1l1Z3dQSTIybnExOUxLd3lpZTVfZll0bkNXZXBuM1hoYWFLX0w2R0pZaUpzaDBOTDBhb3pmTVBkRTVQRC12X3FnbUgxLXZYdGVmcHhfaFU0aUZNZVMxNHhFUk5OblJyMmxYTUpDa2RFYTdISXNCR2swdHhaaGF0NUt4UDR3cWZTamRwcVFfQ19sa1RUek5fU0taUTYtMjlzTkdnLUVWb3oxMUZWc3Q2OEx2ZnlIY0V0eFp0ZUxacXpiWmh6MzZrVl83VmFGd0FqVnVkTGFQN2VzT3ZRcmlTQ2pLUE5XbVcyNWhudzIzejJBSnVURW00YWR1cmN6a3ZLWU1icTd2SnN0SVdJV09RIiwib2F1dGhfdG9rZW4iOiJFQUFCd3pMaXhuallCQUJBZmJuQ3haQzZMd3h4MDFJV2MyZ3dsQ3k3Qmp0b05UNUY0WDY2NHBrUzRQeERNVXRsdmhWWkI3SXE0MGsyZ2hJQm55RHRPcW5iVjlPbUNiWGhyTFBaQUhBQjFzVFpBdHF6RFEzVTROUkhOU1V6MFVXWkNtTEdLcDNNWDRoazVIOURLbERHN0QwUlhZNHY4dHBCdVNNYjN4dnBTRGtQcHdYRlBXVU82VCIsImFsZ29yaXRobSI6IkhNQUMtU0hBMjU2IiwiaXNzdWVkX2F0IjoxNjI0NjIxOTgxfQ; csrftoken=PpiPMEl0R2pAwThsw4NXynO6cVIXHZDo; ds_user_id=38316792800; sessionid=38316792800:rQj5Tr3g5zkg7b:4; rur=\"RVA\05438316792800\0541656158332:01f759cf624bef147397144805bb4c26f6c8b36a232e0f5738c570ee492f6b629f84f6e5\"" 141 | } 142 | }) 143 | .then( async data => { 144 | const user = data.graphql.user 145 | let result = { 146 | message: 'By Naze', 147 | id: user.id, 148 | biography: user.biography, 149 | followers: user.edge_followed_by.count, 150 | following: user.edge_follow.count, 151 | fullName: user.full_name, 152 | highlightCount: user.highlight_reel_count, 153 | isBusinessAccount: user.is_business_account, 154 | isRecentUser: user.is_joined_recently, 155 | accountCategory: user.business_category_name, 156 | linkedFacebookPage: user.connected_fb_page, 157 | isPrivate: user.is_private, 158 | isVerified: user.is_verified, 159 | profilePicHD: user.profile_pic_url_hd, 160 | username: user.username, 161 | postsCount: user.edge_owner_to_timeline_media.count 162 | } 163 | resolve(result) 164 | }) 165 | .catch(reject) 166 | }) 167 | } 168 | 169 | function aiovideodl(link) { 170 | return new Promise((resolve, reject) => { 171 | axios({ 172 | url: 'https://aiovideodl.ml/', 173 | method: 'GET', 174 | headers: { 175 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", 176 | "cookie": "PHPSESSID=69ce1f8034b1567b99297eee2396c308; _ga=GA1.2.1360894709.1632723147; _gid=GA1.2.1782417082.1635161653" 177 | } 178 | }).then((src) => { 179 | let a = cheerio.load(src.data) 180 | let token = a('#token').attr('value') 181 | axios({ 182 | url: 'https://aiovideodl.ml/wp-json/aio-dl/video-data/', 183 | method: 'POST', 184 | headers: { 185 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", 186 | "cookie": "PHPSESSID=69ce1f8034b1567b99297eee2396c308; _ga=GA1.2.1360894709.1632723147; _gid=GA1.2.1782417082.1635161653" 187 | }, 188 | data: new URLSearchParams(Object.entries({ 'url': link, 'token': token })) 189 | }).then(({ data }) => { 190 | resolve(data) 191 | }) 192 | }) 193 | }) 194 | } 195 | 196 | function umma(url) { 197 | return new Promise((resolve, reject) => { 198 | axios.get(url) 199 | .then((res) => { 200 | let $ = cheerio.load(res.data) 201 | let image = [] 202 | $('#article-content > div').find('img').each(function (a, b) { 203 | image.push($(b).attr('src')) 204 | }) 205 | let hasil = { 206 | title: $('#wrap > div.content-container.font-6-16 > h1').text().trim(), 207 | author: { 208 | name: $('#wrap > div.content-container.font-6-16 > div.content-top > div > div.user-ame.font-6-16.fw').text().trim(), 209 | profilePic: $('#wrap > div.content-container.font-6-16 > div.content-top > div > div.profile-photo > img.photo').attr('src') 210 | }, 211 | caption: $('#article-content > div > p').text().trim(), 212 | media: $('#article-content > div > iframe').attr('src') ? [$('#article-content > div > iframe').attr('src')] : image, 213 | type: $('#article-content > div > iframe').attr('src') ? 'video' : 'image', 214 | like: $('#wrap > div.bottom-btns > div > button:nth-child(1) > div.text.font-6-12').text(), 215 | } 216 | resolve(hasil) 217 | }) 218 | }) 219 | } 220 | 221 | function ringtone(title) { 222 | return new Promise((resolve, reject) => { 223 | axios.get('https://meloboom.com/en/search/'+title) 224 | .then((get) => { 225 | let $ = cheerio.load(get.data) 226 | let hasil = [] 227 | $('#__next > main > section > div.jsx-2244708474.container > div > div > div > div:nth-child(4) > div > div > div > ul > li').each(function (a, b) { 228 | hasil.push({ title: $(b).find('h4').text(), source: 'https://meloboom.com/'+$(b).find('a').attr('href'), audio: $(b).find('audio').attr('src') }) 229 | }) 230 | resolve(hasil) 231 | }) 232 | }) 233 | } 234 | 235 | function styletext(teks) { 236 | return new Promise((resolve, reject) => { 237 | axios.get('http://qaz.wtf/u/convert.cgi?text='+teks) 238 | .then(({ data }) => { 239 | let $ = cheerio.load(data) 240 | let hasil = [] 241 | $('table > tbody > tr').each(function (a, b) { 242 | hasil.push({ name: $(b).find('td:nth-child(1) > span').text(), result: $(b).find('td:nth-child(2)').text().trim() }) 243 | }) 244 | resolve(hasil) 245 | }) 246 | }) 247 | } 248 | 249 | module.exports = { pinterest, wallpaper, wikimedia, porno, hentai, quotesAnime, igstalk, aiovideodl, umma, ringtone, styletext } 250 | -------------------------------------------------------------------------------- /lib/textpro.js: -------------------------------------------------------------------------------- 1 | //════════════════════════════// 2 | //If you want to recode, reupload 3 | //or copy the codes/script, 4 | //pls give credit 5 | //no credit? i will take action immediately 6 | //© 2022 Xeon Bot Inc. Cheems Bot MD 7 | //Thank you to Lord Buddha, Family and Myself 8 | //════════════════════════════// 9 | //recode kar ke youtube pe upload kar rhe ya 10 | //codes copy kar ke apne script me dal rhe 11 | //hai to, description me xeon ka yt channel 12 | // ka link paste kr dena as a cradit or github 13 | //repo me bhi tag kardena baki jo 14 | //bhi karna hai apki marzi, thank you!🦄 15 | //════════════════════════════// 16 | //If you recode and uploading on your channel 17 | //or copy pasting the codes in ur script, 18 | //i give permission to do as long as you 19 | //put Xeons youtube channel link in the video 20 | //description and tag me on githuh repo, 21 | //thank you🦄 22 | //════════════════════════════// 23 | const fetch = require("node-fetch"); 24 | const cheerio = require("cheerio"); 25 | const cookie = require("cookie"); 26 | const FormData = require("form-data"); 27 | 28 | async function post(url, formdata = {}, cookies) { 29 | let encode = encodeURIComponent; 30 | let body = Object.keys(formdata) 31 | .map((key) => { 32 | let vals = formdata[key]; 33 | let isArray = Array.isArray(vals); 34 | let keys = encode(key + (isArray ? "[]" : "")); 35 | if (!isArray) vals = [vals]; 36 | let out = []; 37 | for (let valq of vals) out.push(keys + "=" + encode(valq)); 38 | return out.join("&"); 39 | }) 40 | .join("&"); 41 | return await fetch(`${url}?${body}`, { 42 | method: "GET", 43 | headers: { 44 | Accept: "*/*", 45 | "Accept-Language": "en-US,en;q=0.9", 46 | "User-Agent": "GoogleBot", 47 | Cookie: cookies, 48 | }, 49 | }); 50 | } 51 | 52 | /** 53 | * TextPro Scraper 54 | * @function 55 | * @param {String} url - Your phootoxy url, example https://photooxy.com/logo-and-text-effects/make-tik-tok-text-effect-375.html. 56 | * @param {String[]} text - Text (required). example ["text", "text 2 if any"] 57 | */ 58 | 59 | async function textpro(url, text) { 60 | if (!/^https:\/\/textpro\.me\/.+\.html$/.test(url)) 61 | throw new Error("Url Salah!!"); 62 | const geturl = await fetch(url, { 63 | method: "GET", 64 | headers: { 65 | "User-Agent": "GoogleBot", 66 | }, 67 | }); 68 | const caritoken = await geturl.text(); 69 | let hasilcookie = geturl.headers 70 | .get("set-cookie") 71 | .split(",") 72 | .map((v) => cookie.parse(v)) 73 | .reduce((a, c) => { 74 | return { ...a, ...c }; 75 | }, {}); 76 | hasilcookie = { 77 | __cfduid: hasilcookie.__cfduid, 78 | PHPSESSID: hasilcookie.PHPSESSID, 79 | }; 80 | hasilcookie = Object.entries(hasilcookie) 81 | .map(([name, value]) => cookie.serialize(name, value)) 82 | .join("; "); 83 | const $ = cheerio.load(caritoken); 84 | const token = $('input[name="token"]').attr("value"); 85 | const form = new FormData(); 86 | if (typeof text === "string") text = [text]; 87 | for (let texts of text) form.append("text[]", texts); 88 | form.append("submit", "Go"); 89 | form.append("token", token); 90 | form.append("build_server", "https://textpro.me"); 91 | form.append("build_server_id", 1); 92 | const geturl2 = await fetch(url, { 93 | method: "POST", 94 | headers: { 95 | Accept: "*/*", 96 | "Accept-Language": "en-US,en;q=0.9", 97 | "User-Agent": "GoogleBot", 98 | Cookie: hasilcookie, 99 | ...form.getHeaders(), 100 | }, 101 | body: form.getBuffer(), 102 | }); 103 | const caritoken2 = await geturl2.text(); 104 | const token2 = /(.*?)<\/div>/.exec(caritoken2); 105 | if (!token2) throw new Error("Token Tidak Ditemukan!!"); 106 | const prosesimage = await post( 107 | "https://textpro.me/effect/create-image", 108 | JSON.parse(token2[1]), 109 | hasilcookie 110 | ); 111 | const hasil = await prosesimage.json(); 112 | return `https://textpro.me${hasil.fullsize_image}`; 113 | } 114 | 115 | module.exports = textpro 116 | -------------------------------------------------------------------------------- /lib/tictactoe.d.ts: -------------------------------------------------------------------------------- 1 | export declare class TicTacToe { 2 | /* X PlayerName */ 3 | playerX: string; 4 | /* Y PlayerName */ 5 | playerY: string; 6 | /* X if true, Y if false */ 7 | _currentTurn: boolean; 8 | _x: number; 9 | _y: number; 10 | _turns: number; 11 | constructor(playerX: string, playerY: string); 12 | get board(): number; 13 | turn(player, index: number): boolean; 14 | turn(player, x: number, y: number): boolean; 15 | } -------------------------------------------------------------------------------- /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/uploader.js: -------------------------------------------------------------------------------- 1 | let axios = require('axios') 2 | let BodyForm = require('form-data') 3 | let { fromBuffer } = require('file-type') 4 | let fetch = require('node-fetch') 5 | let fs = require('fs') 6 | let cheerio = require('cheerio') 7 | 8 | 9 | 10 | function TelegraPh (Path) { 11 | return new Promise (async (resolve, reject) => { 12 | if (!fs.existsSync(Path)) return reject(new Error("File not Found")) 13 | try { 14 | const form = new BodyForm(); 15 | form.append("file", fs.createReadStream(Path)) 16 | const data = await axios({ 17 | url: "https://telegra.ph/upload", 18 | method: "POST", 19 | headers: { 20 | ...form.getHeaders() 21 | }, 22 | data: form 23 | }) 24 | return resolve("https://telegra.ph" + data.data[0].src) 25 | } catch (err) { 26 | return reject(new Error(String(err))) 27 | } 28 | }) 29 | } 30 | 31 | async function UploadFileUgu (input) { 32 | return new Promise (async (resolve, reject) => { 33 | const form = new BodyForm(); 34 | form.append("files[]", fs.createReadStream(input)) 35 | await axios({ 36 | url: "https://uguu.se/upload.php", 37 | method: "POST", 38 | headers: { 39 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36", 40 | ...form.getHeaders() 41 | }, 42 | data: form 43 | }).then((data) => { 44 | resolve(data.data.files[0]) 45 | }).catch((err) => reject(err)) 46 | }) 47 | } 48 | 49 | function webp2mp4File(path) { 50 | return new Promise((resolve, reject) => { 51 | const form = new BodyForm() 52 | form.append('new-image-url', '') 53 | form.append('new-image', fs.createReadStream(path)) 54 | axios({ 55 | method: 'post', 56 | url: 'https://s6.ezgif.com/webp-to-mp4', 57 | data: form, 58 | headers: { 59 | 'Content-Type': `multipart/form-data; boundary=${form._boundary}` 60 | } 61 | }).then(({ data }) => { 62 | const bodyFormThen = new BodyForm() 63 | const $ = cheerio.load(data) 64 | const file = $('input[name="file"]').attr('value') 65 | bodyFormThen.append('file', file) 66 | bodyFormThen.append('convert', "Convert WebP to MP4!") 67 | axios({ 68 | method: 'post', 69 | url: 'https://ezgif.com/webp-to-mp4/' + file, 70 | data: bodyFormThen, 71 | headers: { 72 | 'Content-Type': `multipart/form-data; boundary=${bodyFormThen._boundary}` 73 | } 74 | }).then(({ data }) => { 75 | const $ = cheerio.load(data) 76 | const result = 'https:' + $('div#output > p.outfile > video > source').attr('src') 77 | resolve({ 78 | status: true, 79 | message: "Created By MRHRTZ", 80 | result: result 81 | }) 82 | }).catch(reject) 83 | }).catch(reject) 84 | }) 85 | } 86 | 87 | async function floNime(medianya, options = {}) { 88 | const { ext } = await fromBuffer(medianya) || options.ext 89 | var form = new BodyForm() 90 | form.append('file', medianya, 'tmp.'+ext) 91 | jsonnya = await fetch('https://flonime.my.id/upload', { 92 | method: 'POST', 93 | body: form 94 | }) 95 | .then((response) => response.json()) 96 | .then((result) => { 97 | return result 98 | }) 99 | .catch(e => { 100 | return e 101 | }) 102 | return jsonnya 103 | } 104 | 105 | module.exports = { TelegraPh, UploadFileUgu, webp2mp4File, floNime } 106 | -------------------------------------------------------------------------------- /lib/y2mate.js: -------------------------------------------------------------------------------- 1 | let fetch = require('node-fetch') 2 | let { JSDOM } = require('jsdom') 3 | 4 | function post(url, formdata) { 5 | return fetch(url, { 6 | method: 'POST', 7 | headers: { 8 | accept: "*/*", 9 | 'accept-language': "en-US,en;q=0.9", 10 | 'content-type': "application/x-www-form-urlencoded; charset=UTF-8" 11 | }, 12 | body: new URLSearchParams(Object.entries(formdata)) 13 | }) 14 | } 15 | const ytIdRegex = /(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})/ 16 | 17 | /** 18 | * Download YouTube Video via y2mate 19 | * @param {String} url YouTube Video URL 20 | * @param {String} quality (avaiable: `144p`, `240p`, `360p`, `480p`, `720p`, `1080p`, `1440p`, `2160p`) 21 | * @param {String} type (avaiable: `mp3`, `mp4`) 22 | * @param {String} bitrate (avaiable for video: `144`, `240`, `360`, `480`, `720`, `1080`, `1440`, `2160`) 23 | * (avaiable for audio: `128`) 24 | * @param {String} server (avaiable: `id4`, `en60`, `en61`, `en68`) 25 | */ 26 | async function yt(url, quality, type, bitrate, server = 'en68') { 27 | let ytId = ytIdRegex.exec(url) 28 | url = 'https://youtu.be/' + ytId[1] 29 | let res = await post(`https://www.y2mate.com/mates/${server}/analyze/ajax`, { 30 | url, 31 | q_auto: 0, 32 | ajax: 1 33 | }) 34 | let json = await res.json() 35 | let { document } = (new JSDOM(json.result)).window 36 | let tables = document.querySelectorAll('table') 37 | let table = tables[{ mp4: 0, mp3: 1 }[type] || 0] 38 | let list 39 | switch (type) { 40 | case 'mp4': 41 | list = Object.fromEntries([...table.querySelectorAll('td > a[href="#"]')].filter(v => !/\.3gp/.test(v.innerHTML)).map(v => [v.innerHTML.match(/.*?(?=\()/)[0].trim(), v.parentElement.nextSibling.nextSibling.innerHTML])) 42 | break 43 | case 'mp3': 44 | list = { 45 | '128kbps': table.querySelector('td > a[href="#"]').parentElement.nextSibling.nextSibling.innerHTML 46 | } 47 | break 48 | default: 49 | list = {} 50 | } 51 | let filesize = list[quality] 52 | let id = /var k__id = "(.*?)"/.exec(document.body.innerHTML) || ['', ''] 53 | let thumb = document.querySelector('img').src 54 | let title = document.querySelector('b').innerHTML 55 | let res2 = await post(`https://www.y2mate.com/mates/${server}/convert`, { 56 | type: 'youtube', 57 | _id: id[1], 58 | v_id: ytId[1], 59 | ajax: '1', 60 | token: '', 61 | ftype: type, 62 | fquality: bitrate 63 | }) 64 | let json2 = await res2.json() 65 | let KB = parseFloat(filesize) * (1000 * /MB$/.test(filesize)) 66 | let resUrl = /= (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 :func:`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.utcnow().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('*• SPEEDTEST.NET*\n\n', 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('Testing from %(isp)s (%(ip)s)...' % speedtest.config['client'], 1914 | quiet) 1915 | 1916 | if not args.mini: 1917 | printer('Retrieving speedtest.net server list...', 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('Selecting best server based on ping...', 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('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: ' 1945 | '%(latency)s ms' % results.server, quiet) 1946 | 1947 | if args.download: 1948 | printer('Testing download speed\n', quiet, 1949 | end=('', '\n')[bool(debug)]) 1950 | speedtest.download( 1951 | callback=callback, 1952 | threads=(None, 1)[args.single] 1953 | ) 1954 | printer('Download: %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 | printer('Testing upload speed\n', quiet, 1963 | end=('', '\n')[bool(debug)]) 1964 | speedtest.upload( 1965 | callback=callback, 1966 | pre_allocate=args.pre_allocate, 1967 | threads=(None, 1)[args.single] 1968 | ) 1969 | printer('Upload: %0.2f M%s/s' % 1970 | ((results.upload / 1000.0 / 1000.0) / args.units[1], 1971 | args.units[0]), 1972 | quiet) 1973 | else: 1974 | printer('Skipping upload test', quiet) 1975 | 1976 | printer('Results:\n%r' % results.dict(), debug=True) 1977 | 1978 | if not args.simple and args.share: 1979 | results.share() 1980 | 1981 | if args.simple: 1982 | printer('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' % 1983 | (results.ping, 1984 | (results.download / 1000.0 / 1000.0) / args.units[1], 1985 | args.units[0], 1986 | (results.upload / 1000.0 / 1000.0) / args.units[1], 1987 | args.units[0])) 1988 | elif args.csv: 1989 | printer(results.csv(delimiter=args.csv_delimiter)) 1990 | elif args.json: 1991 | printer(results.json()) 1992 | 1993 | if args.share and not machine_format: 1994 | printer('Share results: %s' % results.share()) 1995 | 1996 | 1997 | def main(): 1998 | try: 1999 | shell() 2000 | except KeyboardInterrupt: 2001 | printer('\nCancelling...', error=True) 2002 | except (SpeedtestException, SystemExit): 2003 | e = get_exception() 2004 | # Ignore a successful exit, or argparse exit 2005 | if getattr(e, 'code', 1) not in (0, 2): 2006 | msg = '%s' % e 2007 | if not msg: 2008 | msg = '%r' % e 2009 | raise SystemExit('ERROR: %s' % msg) 2010 | 2011 | 2012 | if __name__ == '__main__': 2013 | main() 2014 | -------------------------------------------------------------------------------- /src/database.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /data/data/com.termux/files/usr/bin/node /data/data/com.termux/files/usr/share/yarn/bin/yarn.js 3 | 4 | PATH: 5 | /data/data/com.termux/files/usr/bin 6 | 7 | Yarn version: 8 | 1.22.19 9 | 10 | Node version: 11 | 18.10.0 12 | 13 | Platform: 14 | android arm64 15 | 16 | Trace: 17 | Error: EACCES: permission denied, symlink '../../../../pino/bin.js' -> '/storage/emulated/0/Download/naze-md/node_modules/@adiwajshing/baileys/node_modules/.bin/pino' 18 | 19 | npm manifest: 20 | { 21 | "name": "naze", 22 | "version": "1.2.3", 23 | "description": "WhatsApp Using Lib Baileys Multi Device", 24 | "main": "index.js", 25 | "type": "commonjs", 26 | "scripts": { 27 | "start": "node index.js" 28 | }, 29 | "keywords": [ 30 | "termux", 31 | "whatsapp", 32 | "2021", 33 | "wabase-md", 34 | "base", 35 | "baileys-md", 36 | "bot", 37 | "bot-md", 38 | "multi-device" 39 | ], 40 | "author": "Naze Dev.", 41 | "license": "MIT", 42 | "dependencies": { 43 | "@adiwajshing/baileys": "^4.1.0", 44 | "@adiwajshing/keyed-db": "^0.2.4", 45 | "@bochilteam/scraper": "^3.0.0", 46 | "awesome-phonenumber": "^2.64.0", 47 | "axios": "^0.24.0", 48 | "chalk": "^4.1.2", 49 | "cheerio": "^1.0.0-rc.10", 50 | "child_process": "^1.0.2", 51 | "cookie": "^0.5.0", 52 | "crypto": "^1.0.1", 53 | "tod-api": "^1.0.5", 54 | "file-type": "^16.5.3", 55 | "fluent-ffmpeg": "^2.1.2", 56 | "fs": "0.0.1-security", 57 | "fs-extra": "^10.0.0", 58 | "got": "^11.8.3", 59 | "emoji-api": "^1.0.2", 60 | "g-i-s": "^2.1.6", 61 | "google-it": "^1.6.2", 62 | "human-readable": "^0.2.1", 63 | "hxz-api": "^1.0.1", 64 | "jimp": "^0.16.1", 65 | "jsdom": "^16.4.0", 66 | "lowdb": "^2.1.0", 67 | "mongoose": "^6.2.1", 68 | "moment-timezone": "^0.5.34", 69 | "ms": "^2.1.3", 70 | "mumaker": "^1.0.0", 71 | "node-cron": "^3.0.0", 72 | "node-fetch": "^2.6.1", 73 | "node-webpmux": "^3.1.0", 74 | "os": "^0.1.2", 75 | "path": "^0.12.7", 76 | "perf_hooks": "0.0.1", 77 | "pino": "^7.0.5", 78 | "qrcode-terminal": "^0.12.0", 79 | "request": "^2.88.2", 80 | "remove.bg": "^1.3.0", 81 | "scrape-primbon": "^1.1.0", 82 | "util": "^0.12.4", 83 | "xfarr-api": "^1.0.2", 84 | "yargs": "^17.2.1", 85 | "yt-search": "^2.10.2" 86 | }, 87 | "directories": { 88 | "lib": "lib", 89 | "src": "src" 90 | }, 91 | "devDependencies": {}, 92 | "repository": { 93 | "type": "git", 94 | "url": "git+https://github.com/nazedev/naze-md.git" 95 | }, 96 | "bugs": { 97 | "url": "https://github.com/nazedev/naze-md/issues" 98 | }, 99 | "homepage": "https://github.com/nazedev/naze-md#readme" 100 | } 101 | 102 | yarn manifest: 103 | No manifest 104 | 105 | Lockfile: 106 | No lockfile 107 | --------------------------------------------------------------------------------