main.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '1'
  2. import './config.js'
  3. import { createRequire } from 'module'
  4. import path, { join } from 'path'
  5. import {fileURLToPath, pathToFileURL} from 'url'
  6. import { platform } from 'process'
  7. import * as ws from 'ws'
  8. import fs, { watchFile, unwatchFile, writeFileSync, readdirSync, statSync, unlinkSync, existsSync, readFileSync, copyFileSync, watch, rmSync, readdir, stat, mkdirSync, rename } from 'fs';
  9. import { promises as fsPromises } from 'fs';
  10. import yargs from 'yargs'
  11. import { spawn } from 'child_process'
  12. import lodash from 'lodash'
  13. import chalk from 'chalk'
  14. import syntaxerror from 'syntax-error'
  15. import { format } from 'util'
  16. import pino from 'pino'
  17. import Pino from 'pino'
  18. import { Boom } from '@hapi/boom'
  19. import { makeWASocket, protoType, serialize } from './lib/simple.js'
  20. import {Low, JSONFile} from 'lowdb'
  21. import PQueue from 'p-queue'
  22. import store from './lib/store.js'
  23. import readline from 'readline'
  24. import NodeCache from 'node-cache'
  25. import { startSubBots } from './plugins/jadibot.js';
  26. import pkg from 'google-libphonenumber'
  27. const { PhoneNumberUtil } = pkg
  28. const phoneUtil = PhoneNumberUtil.getInstance()
  29. const { makeInMemoryStore, DisconnectReason, useMultiFileAuthState, MessageRetryMap, fetchLatestBaileysVersion, makeCacheableSignalKeyStore } = await import('@whiskeysockets/baileys')
  30. const { CONNECTING } = ws
  31. const { chain } = lodash
  32. const PORT = process.env.PORT || process.env.SERVER_PORT || 3000
  33. protoType()
  34. serialize()
  35. global.__filename = function filename(pathURL = import.meta.url, rmPrefix = platform !== 'win32') {
  36. return rmPrefix ? /file:\/\/\//.test(pathURL) ? fileURLToPath(pathURL) : pathURL : pathToFileURL(pathURL).toString();
  37. }; global.__dirname = function dirname(pathURL) {
  38. return path.dirname(global.__filename(pathURL, true));
  39. }; global.__require = function require(dir = import.meta.url) {
  40. return createRequire(dir);
  41. };
  42. //global.API = (name, path = '/', query = {}, apikeyqueryname) => (name in global.APIs ? global.APIs[name] : name) + path + (query || apikeyqueryname ? '?' + new URLSearchParams(Object.entries({...query, ...(apikeyqueryname ? {[apikeyqueryname]: global.APIKeys[name in global.APIs ? global.APIs[name] : name]} : {})})) : '')
  43. global.timestamp = { start: new Date }
  44. const __dirname = global.__dirname(import.meta.url);
  45. //const __dirname = join(fileURLToPath(import.meta.url), '..');
  46. global.opts = new Object(yargs(process.argv.slice(2)).exitProcess(false).parse());
  47. //global.prefix = new RegExp('^[' + (opts['prefix'] || '*/i!#$%+£¢€¥^°=¶∆×÷π√✓©®&.\\-.@').replace(/[|\\{}()[\]^$+*.\-\^]/g, '\\$&') + ']')
  48. //news
  49. const databasePath = path.join(__dirname, 'database');
  50. if (!fs.existsSync(databasePath)) fs.mkdirSync(databasePath);
  51. const paths = {
  52. users: path.join(databasePath, 'users'),
  53. chats: path.join(databasePath, 'chats'),
  54. settings: path.join(databasePath, 'settings'),
  55. msgs: path.join(databasePath, 'msgs'),
  56. sticker: path.join(databasePath, 'sticker'),
  57. stats: path.join(databasePath, 'stats'),
  58. };
  59. Object.values(paths).forEach(dir => {
  60. if (!fs.existsSync(dir)) fs.mkdirSync(dir);
  61. });
  62. const queue = new PQueue({ concurrency: 5 });
  63. global.db = {
  64. data: {
  65. users: {},
  66. chats: {},
  67. settings: {},
  68. msgs: {},
  69. sticker: {},
  70. stats: {},
  71. },
  72. };
  73. function getFilePath(category, id) {
  74. return path.join(paths[category], `${id}.json`);
  75. }
  76. async function readFile(category, id) {
  77. const filePath = getFilePath(category, id);
  78. const db = new Low(new JSONFile(filePath));
  79. await db.read();
  80. db.data = db.data || {};
  81. return db.data;
  82. }
  83. async function writeFile(category, id, data) {
  84. const filePath = getFilePath(category, id);
  85. const db = new Low(new JSONFile(filePath));
  86. await db.read();
  87. db.data = { ...db.data, ...data };
  88. await db.write();
  89. }
  90. global.db.readData = async function (category, id) {
  91. if (!global.db.data[category][id]) {
  92. const data = await queue.add(() => readFile(category, id));
  93. global.db.data[category][id] = data;
  94. }
  95. return global.db.data[category][id];
  96. };
  97. global.db.writeData = async function (category, id, data) {
  98. global.db.data[category][id] = { ...global.db.data[category][id], ...data };
  99. await queue.add(() => writeFile(category, id, global.db.data[category][id]));
  100. };
  101. global.db.loadDatabase = async function () {
  102. const categories = ['users', 'chats', 'settings', 'msgs', 'sticker', 'stats'];
  103. const loadPromises = [];
  104. for (const category of categories) {
  105. const files = fs.readdirSync(paths[category]);
  106. for (const file of files) {
  107. const id = path.basename(file, '.json');
  108. if (category === 'users' && (id.includes('@newsletter') || id.includes('lid'))) continue;
  109. if (category === 'chats' && id.includes('@newsletter')) continue;
  110. loadPromises.push(queue.add(() => readFile(category, id)).then(data => {
  111. global.db.data[category][id] = data;
  112. }).catch(err => console.error(`Error cargando ${category}/${id}:`, err))
  113. );
  114. }}
  115. await Promise.all(loadPromises);
  116. console.log('Base de datos cargada');
  117. };
  118. global.db.save = async function () {
  119. const categories = ['users', 'chats', 'settings', 'msgs', 'sticker', 'stats'];
  120. for (const category of categories) {
  121. for (const [id, data] of Object.entries(global.db.data[category])) {
  122. if (Object.keys(data).length > 0) {
  123. if (category === 'users' && (id.includes('@newsletter') || id.includes('lid'))) continue;
  124. if (category === 'chats' && id.includes('@newsletter')) continue;
  125. await queue.add(() => writeFile(category, id, data))
  126. }}}};
  127. global.db.loadDatabase().then(() => {
  128. }).catch(err => console.error(err));
  129. /*global.db = new Low(/https?:\/\//.test(opts['db'] || '') ? new cloudDBAdapter(opts['db']) : new JSONFile('database.json'))
  130. global.DATABASE = global.db;
  131. global.loadDatabase = async function loadDatabase() {
  132. if (global.db.READ) {
  133. return new Promise((resolve) => setInterval(async function() {
  134. if (!global.db.READ) {
  135. clearInterval(this);
  136. resolve(global.db.data == null ? global.loadDatabase() : global.db.data);
  137. }}, 1 * 1000));
  138. }
  139. if (global.db.data !== null) return;
  140. global.db.READ = true;
  141. await global.db.read().catch(console.error);
  142. global.db.READ = null;
  143. global.db.data = {
  144. users: {},
  145. chats: {},
  146. stats: {},
  147. msgs: {},
  148. sticker: {},
  149. settings: {},
  150. ...(global.db.data || {}),
  151. };
  152. global.db.chain = chain(global.db.data);
  153. };
  154. loadDatabase();*/
  155. //if (global.conns instanceof Array) {console.log('Conexiones ya inicializadas...');} else {global.conns = [];}
  156. /* ------------------------------------------------*/
  157. global.creds = 'creds.json'
  158. global.authFile = `BotSession`
  159. global.authFileJB = 'jadibts'
  160. global.rutaBot = join(__dirname, authFile)
  161. global.rutaJadiBot = join(__dirname, authFileJB)
  162. const respaldoDir = join(__dirname, 'BackupSession');
  163. const credsFile = join(global.rutaBot, global.creds);
  164. const backupFile = join(respaldoDir, global.creds);
  165. if (!fs.existsSync(rutaJadiBot)) {
  166. fs.mkdirSync(rutaJadiBot)}
  167. if (!fs.existsSync(respaldoDir)) fs.mkdirSync(respaldoDir);
  168. const {state, saveState, saveCreds} = await useMultiFileAuthState(global.authFile)
  169. const msgRetryCounterMap = new Map();
  170. const msgRetryCounterCache = new NodeCache({ stdTTL: 0, checkperiod: 0 });
  171. const userDevicesCache = new NodeCache({ stdTTL: 0, checkperiod: 0 });
  172. const {version} = await fetchLatestBaileysVersion()
  173. let phoneNumber = global.botNumberCode
  174. const methodCodeQR = process.argv.includes("qr")
  175. const methodCode = !!phoneNumber || process.argv.includes("code")
  176. const MethodMobile = process.argv.includes("mobile")
  177. let rl = readline.createInterface({
  178. input: process.stdin,
  179. output: process.stdout,
  180. terminal: true,
  181. })
  182. const question = (texto) => {
  183. rl.clearLine(rl.input, 0)
  184. return new Promise((resolver) => {
  185. rl.question(texto, (respuesta) => {
  186. rl.clearLine(rl.input, 0)
  187. resolver(respuesta.trim())
  188. })})
  189. }
  190. let opcion
  191. if (methodCodeQR) {
  192. opcion = '1'
  193. }
  194. if (!methodCodeQR && !methodCode && !fs.existsSync(`./${authFile}/creds.json`)) {
  195. do {
  196. let lineM = '⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ 》'
  197. opcion = await question(`╭${lineM}
  198. ┊ ${chalk.blueBright('╭┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅')}
  199. ┊ ${chalk.blueBright('┊')} ${chalk.blue.bgBlue.bold.cyan('MÉTODO DE VINCULACIÓN')}
  200. ┊ ${chalk.blueBright('╰┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅')}
  201. ┊ ${chalk.blueBright('╭┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅')}
  202. ┊ ${chalk.blueBright('┊')} ${chalk.green.bgMagenta.bold.yellow('¿CÓMO DESEA CONECTARSE?')}
  203. ┊ ${chalk.blueBright('┊')} ${chalk.bold.redBright('⇢ Opción 1:')} ${chalk.greenBright('Código QR.')}
  204. ┊ ${chalk.blueBright('┊')} ${chalk.bold.redBright('⇢ Opción 2:')} ${chalk.greenBright('Código de 8 digitos.')}
  205. ┊ ${chalk.blueBright('╰┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅')}
  206. ┊ ${chalk.blueBright('╭┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅')}
  207. ┊ ${chalk.blueBright('┊')} ${chalk.italic.magenta('Escriba sólo el número de')}
  208. ┊ ${chalk.blueBright('┊')} ${chalk.italic.magenta('la opción para conectarse.')}
  209. ┊ ${chalk.blueBright('╰┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅')}
  210. ╰${lineM}\n${chalk.bold.magentaBright('---> ')}`)
  211. if (!/^[1-2]$/.test(opcion)) {
  212. console.log(chalk.bold.redBright(`NO SE PERMITE NÚMEROS QUE NO SEAN ${chalk.bold.greenBright("1")} O ${chalk.bold.greenBright("2")}, TAMPOCO LETRAS O SÍMBOLOS ESPECIALES. ${chalk.bold.yellowBright("CONSEJO: COPIE EL NÚMERO DE LA OPCIÓN Y PÉGUELO EN LA CONSOLA.")}`))
  213. }} while (opcion !== '1' && opcion !== '2' || fs.existsSync(`./${authFile}/creds.json`))
  214. }
  215. console.info = () => {}
  216. /*const connectionOptions = {
  217. logger: pino({ level: 'silent' }),
  218. printQRInTerminal: opcion == '1' ? true : methodCodeQR ? true : false,
  219. mobile: MethodMobile,
  220. browser: opcion == '1' ? ['KANTU-MD', 'Edge', '20.0.04'] : methodCodeQR ? ['KANTU-MD', 'Edge', '20.0.04'] : ["Ubuntu", "Chrome", "20.0.04"],
  221. auth: {
  222. creds: state.creds,
  223. keys: makeCacheableSignalKeyStore(state.keys, Pino({ level: "fatal" }).child({ level: "fatal" })),
  224. },
  225. markOnlineOnConnect: false,
  226. generateHighQualityLinkPreview: true,
  227. syncFullHistory: false,
  228. getMessage: async (key) => {
  229. try {
  230. let jid = jidNormalizedUser(key.remoteJid);
  231. let msg = await store.loadMessage(jid, key.id);
  232. return msg?.message || "";
  233. } catch (error) {
  234. return "";
  235. }},
  236. msgRetryCounterCache: msgRetryCounterCache || new Map(),
  237. userDevicesCache: userDevicesCache || new Map(),
  238. //msgRetryCounterMap,
  239. defaultQueryTimeoutMs: undefined,
  240. cachedGroupMetadata: (jid) => global.conn.chats[jid] ?? {},
  241. version: [2, 3000, 1015901307],
  242. };*/
  243. const connectionOptions = {
  244. logger: pino({ level: 'silent' }),
  245. printQRInTerminal: opcion == '1' ? true : methodCodeQR ? true : false,
  246. mobile: MethodMobile,
  247. auth: {
  248. creds: state.creds,
  249. keys: makeCacheableSignalKeyStore(state.keys, Pino({ level: "fatal" }).child({ level: "fatal" })),
  250. },
  251. browser: opcion == '1' ? ['KantuBot', 'Edge', '20.0.04'] : methodCodeQR ? ['KantuBot', 'Edge', '20.0.04'] : ["Ubuntu", "Chrome", "20.0.04"],
  252. version: version,
  253. generateHighQualityLinkPreview: true
  254. };
  255. global.conn = makeWASocket(connectionOptions)
  256. if (!fs.existsSync(`./${authFile}/creds.json`)) {
  257. if (opcion === '2' || methodCode) {
  258. opcion = '2'
  259. if (!conn.authState.creds.registered) {
  260. let addNumber
  261. if (!!phoneNumber) {
  262. addNumber = phoneNumber.replace(/[^0-9]/g, '')
  263. } else {
  264. do {
  265. phoneNumber = await question(chalk.bgBlack(chalk.bold.greenBright("\n\n✳️ Escriba su número\n\nEjemplo: 5491168xxxx\n\n\n\n")))
  266. phoneNumber = phoneNumber.replace(/\D/g,'')
  267. if (!phoneNumber.startsWith('+')) {
  268. phoneNumber = `+${phoneNumber}`
  269. }
  270. } while (!await isValidPhoneNumber(phoneNumber))
  271. rl.close()
  272. addNumber = phoneNumber.replace(/\D/g, '')
  273. setTimeout(async () => {
  274. let codeBot = await conn.requestPairingCode(addNumber)
  275. codeBot = codeBot?.match(/.{1,4}/g)?.join("-") || codeBot
  276. console.log(chalk.bold.white(chalk.bgMagenta(`CÓDIGO DE VINCULACIÓN:`)), chalk.bold.white(chalk.white(codeBot)))
  277. }, 2000)
  278. }}}
  279. }
  280. conn.isInit = false
  281. conn.well = false
  282. if (!opts['test']) {
  283. setInterval(async () => {
  284. if (global.db.data) await global.db.save();
  285. if (opts['autocleartmp'] && (global.support || {}).find) {
  286. const tmpDirs = [os.tmpdir(), 'tmp', "jadibts"];
  287. tmpDirs.forEach(dir => {
  288. cp.spawn('find', [dir, '-amin', '2', '-type', 'f', '-delete']);
  289. })}}, 30 * 1000)}
  290. if (opts['server']) (await import('./server.js')).default(global.conn, PORT)
  291. //respaldo de la sesión
  292. function manageCredentials(action) {
  293. const credsFile = join(global.rutaBot, global.creds);
  294. const backupFile = join(respaldoDir, global.creds);
  295. if (action === 'backup' && existsSync(credsFile)) {
  296. copyFileSync(credsFile, backupFile);
  297. console.log(`[✅] Respaldo creado en ${backupFile}`);
  298. } else if (action === 'restore' && existsSync(backupFile)) {
  299. copyFileSync(backupFile, credsFile);
  300. console.log(`[✅] creds.json restaurado desde el respaldo`);
  301. }
  302. }
  303. setInterval(() => manageCredentials('backup'), 5 * 60 * 1000);
  304. //tmp
  305. async function cleanUp(type) {
  306. const targets = {
  307. tmp: join(__dirname, 'tmp'),
  308. session: './BotSession',
  309. subbots: './jadibts/'
  310. };
  311. if (type === 'tmp') {
  312. const files = readdirSync(targets.tmp);
  313. files.forEach(file => unlinkSync(join(targets.tmp, file)));
  314. console.log(chalk.cyan(`┏━━━━━━⪻♻️ AUTO-CLEAR 🗑️⪼━━━━━━•\n┃→ ARCHIVOS DE LA CARPETA TMP ELIMINADOS\n┗━━━━━━━━━━━━━━━━━━━━━━━━━━━•`));
  315. } else if (type === 'session' || type === 'subbots') {
  316. const dir = targets[type];
  317. const files = readdirSync(dir).filter(f => f.startsWith('pre-key-'));
  318. const threshold = Date.now() - (24 * 60 * 60 * 1000);
  319. for (const file of files) {
  320. const filePath = join(dir, file);
  321. const { mtimeMs } = statSync(filePath);
  322. if (mtimeMs < threshold) await unlinkSync(filePath);
  323. }
  324. console.log(chalk.bold.cyanBright(`\n╭» 🔵 ${type} 🔵\n│→ SESIONES NO ESENCIALES ELIMINADAS\n╰― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― 🗑️♻️`));
  325. }}
  326. setInterval(() => cleanUp('tmp'), 1000 * 60 * 3);
  327. setInterval(() => { cleanUp('session'); cleanUp('subbots'); }, 1000 * 60 * 10);
  328. async function connectionUpdate(update) {
  329. const {connection, lastDisconnect, isNewLogin} = update
  330. global.stopped = connection
  331. if (isNewLogin) conn.isInit = true
  332. const code = lastDisconnect?.error?.output?.statusCode || lastDisconnect?.error?.output?.payload?.statusCode
  333. if (code && code !== DisconnectReason.loggedOut && conn?.ws.socket == null) {
  334. await global.reloadHandler(true).catch(console.error)
  335. //console.log(await global.reloadHandler(true).catch(console.error));
  336. global.timestamp.connect = new Date
  337. }
  338. if (global.db.data == null) loadDatabase()
  339. if (update.qr != 0 && update.qr != undefined || methodCodeQR) {
  340. if (opcion == '1' || methodCodeQR) {
  341. console.log(chalk.cyan('✅ ESCANEA EL CÓDIGO QR EXPIRA EN 45 SEGUNDOS ✅.'))
  342. }}
  343. if (connection == 'open') {
  344. console.log(chalk.bold.greenBright('\n▣─────────────────────────────···\n│\n│❧ 𝙲𝙾𝙽𝙴𝙲𝚃𝙰𝙳𝙾 𝙲𝙾𝚁𝚁𝙴𝙲𝚃𝙰𝙼𝙴𝙽𝚃𝙴 𝙰𝙻 𝚆𝙷𝙰𝚃𝚂𝙰𝙿𝙿 ✅\n│\n▣─────────────────────────────···'))
  345. await joinChannels(conn)
  346. }
  347. let reason = new Boom(lastDisconnect?.error)?.output?.statusCode
  348. if (connection === 'close') {
  349. if (reason === DisconnectReason.badSession) {
  350. conn.logger.error(`[ ⚠ ] Sesión incorrecta, por favor elimina la carpeta ${global.authFile} y escanea nuevamente.`);
  351. } else if (reason === DisconnectReason.connectionClosed) {
  352. conn.logger.warn(`[ ⚠ ] Conexión cerrada, reconectando...`);
  353. manageCredentials('restore');
  354. await global.reloadHandler(true).catch(console.error)
  355. } else if (reason === DisconnectReason.connectionLost) {
  356. conn.logger.warn(`[ ⚠ ] Conexión perdida con el servidor, reconectando...`);
  357. manageCredentials('restore');
  358. await global.reloadHandler(true).catch(console.error)
  359. } else if (reason === DisconnectReason.connectionReplaced) {
  360. conn.logger.error(`[ ⚠ ] Conexión reemplazada, se ha abierto otra nueva sesión. Por favor, cierra la sesión actual primero.`);
  361. } else if (reason === DisconnectReason.loggedOut) {
  362. conn.logger.error(`[ ⚠ ] Conexion cerrada, por favor elimina la carpeta ${global.authFile} y escanea nuevamente.`);
  363. await global.reloadHandler(true).catch(console.error)
  364. } else if (reason === DisconnectReason.restartRequired) {
  365. conn.logger.info(`[ ⚠ ] Reinicio necesario, reinicie el servidor si presenta algún problema.`);
  366. await global.reloadHandler(true).catch(console.error)
  367. } else if (reason === DisconnectReason.timedOut) {
  368. conn.logger.warn(`[ ⚠ ] Tiempo de conexión agotado, reconectando...`);
  369. await global.reloadHandler(true).catch(console.error) //process.send('reset')
  370. } else {
  371. conn.logger.warn(`[ ⚠ ] Razón de desconexión desconocida. ${reason || ''}: ${connection || ''}`);
  372. }}}
  373. process.on('uncaughtException', console.error);
  374. let isInit = true;
  375. let handler = await import('./handler.js');
  376. global.reloadHandler = async function(restatConn) {
  377. try {
  378. const Handler = await import(`./handler.js?update=${Date.now()}`).catch(console.error);
  379. if (Object.keys(Handler || {}).length) handler = Handler;
  380. } catch (e) {
  381. console.error(e);
  382. }
  383. if (restatConn) {
  384. const oldChats = global.conn.chats;
  385. try {
  386. global.conn.ws.close();
  387. } catch { }
  388. conn.ev.removeAllListeners();
  389. global.conn = makeWASocket(connectionOptions, {chats: oldChats});
  390. isInit = true;
  391. }
  392. if (!isInit) {
  393. conn.ev.off('messages.upsert', conn.handler);
  394. conn.ev.off('group-participants.update', conn.participantsUpdate);
  395. conn.ev.off('groups.update', conn.groupsUpdate);
  396. conn.ev.off('message.delete', conn.onDelete);
  397. conn.ev.off('call', conn.onCall);
  398. conn.ev.off('connection.update', conn.connectionUpdate);
  399. conn.ev.off('creds.update', conn.credsUpdate);
  400. }
  401. conn.welcome = 'HOLAA!! @user\n\n『Bienvenido A *@subject*』\n\n_`Recuerda leer las reglas del grupo para no tener ningun problema 🐣`_'
  402. conn.bye = 'Bueno, se fue @user 👋\n\nQue lo atropelle un tren 👻`'
  403. conn.spromote = 'Hey @user ya forma parte de staff 👑'
  404. conn.sdemote = '@user ya no eres admins'
  405. conn.sDesc = 'La descripción ha sido cambiada a \n@desc'
  406. conn.sSubject = 'El nombre del grupo ha sido cambiado a \n@group'
  407. conn.sIcon = 'El icono del grupo ha sido cambiado'
  408. conn.sRevoke = 'El enlace del grupo ha sido cambiado a \n@revoke'
  409. conn.handler = handler.handler.bind(global.conn);
  410. conn.participantsUpdate = handler.participantsUpdate.bind(global.conn);
  411. conn.groupsUpdate = handler.groupsUpdate.bind(global.conn);
  412. conn.onDelete = handler.deleteUpdate.bind(global.conn);
  413. conn.onCall = handler.callUpdate.bind(global.conn);
  414. conn.connectionUpdate = connectionUpdate.bind(global.conn);
  415. conn.credsUpdate = saveCreds.bind(global.conn, true);
  416. conn.ev.on('messages.upsert', conn.handler);
  417. conn.ev.on('group-participants.update', conn.participantsUpdate);
  418. conn.ev.on('groups.update', conn.groupsUpdate);
  419. conn.ev.on('message.delete', conn.onDelete);
  420. conn.ev.on('call', conn.onCall);
  421. conn.ev.on('connection.update', conn.connectionUpdate);
  422. conn.ev.on('creds.update', conn.credsUpdate);
  423. isInit = false
  424. return true
  425. }
  426. //Arranque nativo para subbots
  427. await startSubBots();
  428. /*const pluginFolder = global.__dirname(join(__dirname, './plugins/index'));
  429. const pluginFilter = (filename) => /\.js$/.test(filename);
  430. global.plugins = {};
  431. async function filesInit() {
  432. for (const filename of readdirSync(pluginFolder).filter(pluginFilter)) {
  433. try {
  434. const file = global.__filename(join(pluginFolder, filename));
  435. const module = await import(file);
  436. global.plugins[filename] = module.default || module;
  437. } catch (e) {
  438. conn.logger.error(e);
  439. delete global.plugins[filename];
  440. }}}
  441. filesInit().then((_) => Object.keys(global.plugins)).catch(console.error)*/
  442. const pluginFolder = global.__dirname(join(__dirname, './plugins/index'))
  443. const pluginFilter = (filename) => /\.js$/.test(filename)
  444. global.plugins = {}
  445. async function filesInit() {
  446. for (const filename of readdirSync(pluginFolder).filter(pluginFilter)) {
  447. try {
  448. const file = global.__filename(join(pluginFolder, filename))
  449. const module = await import(file)
  450. global.plugins[filename] = module.default || module
  451. } catch (e) {
  452. conn.logger.error(e)
  453. delete global.plugins[filename]
  454. }}}
  455. filesInit().then((_) => Object.keys(global.plugins)).catch(console.error)
  456. global.reload = async (_ev, filename) => {
  457. if (pluginFilter(filename)) {
  458. const dir = global.__filename(join(pluginFolder, filename), true)
  459. if (filename in global.plugins) {
  460. if (existsSync(dir)) conn.logger.info(` SE ACTULIZADO - '${filename}' CON ÉXITO`)
  461. else {
  462. conn.logger.warn(`SE ELIMINO UN ARCHIVO : '${filename}'`)
  463. return delete global.plugins[filename];
  464. }
  465. } else conn.logger.info(`SE DETECTO UN NUEVO PLUGINS : '${filename}'`)
  466. const err = syntaxerror(readFileSync(dir), filename, {
  467. sourceType: 'module',
  468. allowAwaitOutsideFunction: true,
  469. });
  470. if (err) conn.logger.error(`SE DETECTO UN ERROR DE SINTAXIS | SYNTAX ERROR WHILE LOADING '${filename}'\n${format(err)}`);
  471. else {
  472. try {
  473. const module = (await import(`${global.__filename(dir)}?update=${Date.now()}`));
  474. global.plugins[filename] = module.default || module;
  475. } catch (e) {
  476. conn.logger.error(`HAY UN ERROR REQUIERE EL PLUGINS '${filename}\n${format(e)}'`);
  477. } finally {
  478. global.plugins = Object.fromEntries(Object.entries(global.plugins).sort(([a], [b]) => a.localeCompare(b)));
  479. }}}};
  480. Object.freeze(global.reload);
  481. watch(pluginFolder, global.reload);
  482. await global.reloadHandler();
  483. async function _quickTest() {
  484. const test = await Promise.all([
  485. spawn('ffmpeg'),
  486. spawn('ffprobe'),
  487. spawn('ffmpeg', ['-hide_banner', '-loglevel', 'error', '-filter_complex', 'color', '-frames:v', '1', '-f', 'webp', '-']),
  488. spawn('convert'),
  489. spawn('magick'),
  490. spawn('gm'),
  491. spawn('find', ['--version']),
  492. ].map((p) => {
  493. return Promise.race([
  494. new Promise((resolve) => {
  495. p.on('close', (code) => {
  496. resolve(code !== 127);
  497. });
  498. }),
  499. new Promise((resolve) => {
  500. p.on('error', (_) => resolve(false));
  501. })]);
  502. }));
  503. const [ffmpeg, ffprobe, ffmpegWebp, convert, magick, gm, find] = test;
  504. const s = global.support = {ffmpeg, ffprobe, ffmpegWebp, convert, magick, gm, find};
  505. Object.freeze(global.support);
  506. }
  507. function redefineConsoleMethod(methodName, filterStrings) {
  508. const originalConsoleMethod = console[methodName]
  509. console[methodName] = function() {
  510. const message = arguments[0]
  511. if (typeof message === 'string' && filterStrings.some(filterString => message.includes(atob(filterString)))) {
  512. arguments[0] = ""
  513. }
  514. originalConsoleMethod.apply(console, arguments)
  515. }}
  516. _quickTest().then(() => conn.logger.info('Ƈᴀʀɢᴀɴᴅᴏ....\n'))
  517. .catch(console.error)
  518. async function isValidPhoneNumber(number) {
  519. try {
  520. number = number.replace(/\s+/g, '')
  521. // Si el número empieza con '+521' o '+52 1', quitar el '1'
  522. if (number.startsWith('+521')) {
  523. number = number.replace('+521', '+52'); // Cambiar +521 a +52
  524. } else if (number.startsWith('+52') && number[4] === '1') {
  525. number = number.replace('+52 1', '+52'); // Cambiar +52 1 a +52
  526. }
  527. const parsedNumber = phoneUtil.parseAndKeepRawInput(number)
  528. return phoneUtil.isValidNumber(parsedNumber)
  529. } catch (error) {
  530. return false
  531. }}
  532. async function joinChannels(conn) {
  533. for (const channelId of Object.values(global.ch)) {
  534. await conn.newsletterFollow(channelId).catch(() => {})
  535. }}