├── 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 |
--------------------------------------------------------------------------------