├── KALO GA DIBACA BAKAL ERROR!!!.txt
├── LICENSE
├── Procfile
├── README.md
├── WEEM SYCHYY
├── app.json
├── database
├── database.json
├── dtabasem
├── jadibot
│ └── sych
├── premium.json
├── sampah
│ └── ydaa
├── scommand.json
├── sewa.json
├── thumbList.json
├── totalcmd.json
├── users.json
└── ©YUDA
├── index.js
├── lib
├── binary.js
├── converter.js
├── exif.js
├── function.js
├── game.js
├── math.js
├── naze.js
├── pixiv.js
├── screaper.js
├── sychyy.js
├── test
├── tictactoe.js
├── tts.js
└── uploader.js
├── naze.js
├── node_modules.zip
├── package.json
├── setown.js
├── settings.js
├── speed.py
├── src
├── SYCHYY NO FES NO NEM
├── database.js
├── media
│ ├── SYCHY-BOTz
│ ├── fake.pdf
│ ├── gmbr
│ ├── stc.webp
│ ├── sych.png
│ └── sychy.png
├── message.js
├── nulis
│ ├── font
│ │ ├── Indie-Flower.ttf
│ │ ├── ObelixProBIt-cyr.ttf
│ │ ├── f
│ │ └── impact.ttf
│ ├── images
│ │ ├── buku
│ │ │ ├── b
│ │ │ ├── sebelumkanan.jpg
│ │ │ └── sebelumkiri.jpg
│ │ ├── folio
│ │ │ ├── f
│ │ │ ├── sebelumkanan.jpg
│ │ │ └── sebelumkiri.jpg
│ │ └── i
│ ├── nla
│ └── sychyy.json
├── premium.js
├── s
└── sewa.js
├── start.js
├── sychMedia
├── menu
│ ├── audio.mp3
│ ├── gif.mp4
│ ├── sych.mp4
│ ├── sychy.jpg
│ └── sychyy.js
└── sychyy.js
└── temp_image.png
/KALO GA DIBACA BAKAL ERROR!!!.txt:
--------------------------------------------------------------------------------
1 | ==========================SYCHBOT============================
2 |
3 | hellooww sebelumnya perkenalkan saya adalah yuda (ydoyy).
4 | saya sudah lama bermain bot wa, tapi sekrang sudah lupa semua :).
5 | disini saya membagikan sc no ENC apalah enc pelit banget awokwok!
6 | script nya dari king ©NAZE jangan lupa di subrek saya cuma recode aja hehe.
7 | banyak sekali bug(nguwawur bukan bug wa ya) tapi disini saya hanya ingin
8 | kalian mencoba script yang saya recode dan menambah fitur yang tentunya work ya
9 | karena saya sudah mencobanya
10 | #botwatermux ga perlu panel" an karna panel itu bayar mending yang simpel kan?
11 | lagian run bot buat diri sendiri juga kan?
12 |
13 | ========================================================
14 |
15 | kenapa module nya dipisah?
16 | yaa karnaa ada bug kalo install langsung
17 |
18 | BACA DENGAN TELITI!
19 | $ pkg update && pkg upgrade
20 | $ pkg install git
21 | $ pkg install bash
22 | $ pkg install nodejs
23 | $ pkg install ffmpeg
24 | $ pkg install imagemagick
25 | $ pkg install libvips
26 | $ pkg install yarn
27 | $ pkg install mc
28 | $ termux-setup-storage
29 | $ cd storage
30 | $ cd downloads
31 | $ cd sych
32 | $ cp -r sych $HOME
33 |
34 | ==========================================================
35 |
36 | PERINTAH KE-2!!
37 |
38 | setelah kalian melakukan yarn dan selesai, kalian langsung ekstrak
39 | node_module.zip terserah dimana asal jangan di luar folder download
40 | nah nanti kalo pas (figlet) ada peringatan merah kalian All in aja
41 | jika sudah selesai ganti yang (sharp) jika sharp sudah selesai
42 | jangan langsung di run!
43 | kalian command ini:
44 |
45 | $ npm install --cpu=wasm32 sharp
46 |
47 | jika sudah selesai command:
48 |
49 | $ npm start
50 |
51 | nanti disuruh kasih nomer 62xxxxx dan code pairing xxXXxXX
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Naze
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | worker: npm i -g pm2 && pm2 start index.js && pm2 save && pm2 logs
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Information
2 |
3 |
4 |

5 |

6 |

7 |

8 |

9 |

10 |

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