herramientas-superinspect.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Código adaptado por https://github.com/GataNina-Li
  2. // Código compatible con canales y comunidades de WhatsApp
  3. import { getUrlFromDirectPath } from "@whiskeysockets/baileys";
  4. import _ from "lodash";
  5. import axios from 'axios';
  6. let handler = async (m, { conn, command, usedPrefix, args, text, groupMetadata, isOwner, isROwner }) => {
  7. const channelUrl = text?.match(/(?:https:\/\/)?(?:www\.)?(?:chat\.|wa\.)?whatsapp\.com\/(?:channel\/|joinchat\/)?([0-9A-Za-z]{22,24})/i)?.[1];
  8. let txtBotAdminCh = '\n\n> *Verifique que el Bot sea admin en el canal, de lo contrario no funcionará el comando*';
  9. let thumb = img.getRandom();
  10. let pp, ch, q, mime, buffer, media, inviteUrlch, imageBuffer;
  11. let inviteCode
  12. if (!text) return await m.reply(`*⚠️ Ingrese un enlace de un grupo/comunidad/canal de WhatsApp para obtener información.*`)
  13. const MetadataGroupInfo = async (res, isInviteInfo = false) => {
  14. let nameCommunity = "no pertenece a ninguna Comunidad"
  15. let groupPicture = "No se pudo obtener"
  16. if (res.linkedParent) {
  17. let linkedGroupMeta = await conn.groupMetadata(res.linkedParent).catch(e => { return null })
  18. nameCommunity = linkedGroupMeta ? "\n" + ("`Nombre:` " + linkedGroupMeta.subject || "") : nameCommunity
  19. }
  20. pp = await conn.profilePictureUrl(res.id, 'image').catch(e => { return null })
  21. inviteCode = await conn.groupInviteCode(m.chat).catch(e => { return null })
  22. const formatParticipants = (participants) =>
  23. participants && participants.length > 0
  24. ? participants.map((user, i) => `${i + 1}. @${user.id?.split("@")[0]}${user.admin === "superadmin" ? " (superadmin)" : user.admin === "admin" ? " (admin)" : ""}`).join("\n")
  25. : "No encontrado"
  26. let caption = `🆔 *Identificador del grupo:*\n${res.id || "No encontrado"}\n\n` +
  27. `👑 *Creado por:*\n${res.owner ? `@${res.owner?.split("@")[0]}` : "No encontrado"} ${res.creation ? `el ${formatDate(res.creation)}` : "(Fecha no encontrada)"}\n\n` +
  28. `🏷️ *Nombre:*\n${res.subject || "No encontrado"}\n\n` +
  29. `✏️ *Nombre cambiado por:*\n${res.subjectOwner ? `@${res.subjectOwner?.split("@")[0]}` : "No encontrado"} ${res.subjectTime ? `el ${formatDate(res.subjectTime)}` : "(Fecha no encontrada)"}\n\n` +
  30. `📄 *Descripción:*\n${res.desc || "No encontrado"}\n\n` +
  31. `📝 *Descripción cambiado por:*\n${res.descOwner ? `@${res.descOwner?.split("@")[0]}` : "No encontrado"}\n\n` +
  32. `🗃️ *Id de la descripción:*\n${res.descId || "No encontrado"}\n\n` +
  33. `🖼️ *Imagen del grupo:*\n${pp ? pp : groupPicture}\n\n` +
  34. `💫 *Autor:*\n${res.author || "No encontrado"}\n\n` +
  35. `🎫 *Código de invitación:*\n${res.inviteCode || inviteCode || "No disponible"}\n\n` +
  36. `⌛ *Duración:*\n${res.ephemeralDuration !== undefined ? `${res.ephemeralDuration} segundos` : "Desconocido"}\n\n` +
  37. `🛃 *Admins:*\n` + (res.participants && res.participants.length > 0 ? res.participants.filter(user => user.admin === "admin" || user.admin === "superadmin").map((user, i) => `${i + 1}. @${user.id?.split("@")[0]}${user.admin === "superadmin" ? " (superadmin)" : " (admin)"}`).join("\n") : "No encontrado") + `\n\n` +
  38. `🔰 *Usuarios en total:*\n${res.size || "Cantidad no encontrada"}\n\n` +
  39. `✨ *Información avanzada* ✨\n\n🔎 *Comunidad vinculada al grupo:*\n${res.isCommunity ? "Este grupo es un chat de avisos" : `${res.linkedParent ? "`Id:` " + res.linkedParent : "Este grupo"} ${nameCommunity}`}\n\n` +
  40. `⚠️ *Restricciones:* ${res.restrict ? "✅" : "❌"}\n` +
  41. `📢 *Anuncios:* ${res.announce ? "✅" : "❌"}\n` +
  42. `🏘️ *¿Es comunidad?:* ${res.isCommunity ? "✅" : "❌"}\n` +
  43. `📯 *¿Es anuncio de comunidad?:* ${res.isCommunityAnnounce ? "✅" : "❌"}\n` +
  44. `🤝 *Tiene aprobación de miembros:* ${res.joinApprovalMode ? "✅" : "❌"}\n` +
  45. `🆕 *Puede Agregar futuros miembros:* ${res.memberAddMode ? "✅" : "❌"}\n\n`
  46. return caption.trim()
  47. }
  48. const inviteGroupInfo = async (groupData) => {
  49. const { id, subject, subjectOwner, subjectTime, size, creation, owner, desc, descId, linkedParent, restrict, announce, isCommunity, isCommunityAnnounce, joinApprovalMode, memberAddMode, ephemeralDuration } = groupData
  50. let nameCommunity = "no pertenece a ninguna Comunidad"
  51. let groupPicture = "No se pudo obtener"
  52. if (linkedParent) {
  53. let linkedGroupMeta = await conn.groupMetadata(linkedParent).catch(e => { return null })
  54. nameCommunity = linkedGroupMeta ? "\n" + ("`Nombre:` " + linkedGroupMeta.subject || "") : nameCommunity
  55. }
  56. pp = await conn.profilePictureUrl(id, 'image').catch(e => { return null })
  57. const formatParticipants = (participants) =>
  58. participants && participants.length > 0
  59. ? participants.map((user, i) => `${i + 1}. @${user.id?.split("@")[0]}${user.admin === "superadmin" ? " (superadmin)" : user.admin === "admin" ? " (admin)" : ""}`).join("\n")
  60. : "No encontrado"
  61. let caption = `🆔 *Identificador del grupo:*\n${id || "No encontrado"}\n\n` +
  62. `👑 *Creado por:*\n${owner ? `@${owner?.split("@")[0]}` : "No encontrado"} ${creation ? `el ${formatDate(creation)}` : "(Fecha no encontrada)"}\n\n` +
  63. `🏷️ *Nombre:*\n${subject || "No encontrado"}\n\n` +
  64. `✏️ *Nombre cambiado por:*\n${subjectOwner ? `@${subjectOwner?.split("@")[0]}` : "No encontrado"} ${subjectTime ? `el ${formatDate(subjectTime)}` : "(Fecha no encontrada)"}\n\n` +
  65. `📄 *Descripción:*\n${desc || "No encontrada"}\n\n` +
  66. `💠 *ID de la descripción:*\n${descId || "No encontrado"}\n\n` +
  67. `🖼️ *Imagen del grupo:*\n${pp ? pp : groupPicture}\n\n` +
  68. `🏆 *Miembros destacados:*\n${formatParticipants(groupData.participants)}\n\n` +
  69. `👥 *Destacados total:*\n${size || "Cantidad no encontrada"}\n\n` +
  70. `✨ *Información avanzada* ✨\n\n🔎 *Comunidad vinculada al grupo:*\n${isCommunity ? "Este grupo es un chat de avisos" : `${linkedParent ? "`Id:` " + linkedParent : "Este grupo"} ${nameCommunity}`}\n\n` +
  71. `📢 *Anuncios:* ${announce ? "✅ Si" : "❌ No"}\n` +
  72. `🏘️ *¿Es comunidad?:* ${isCommunity ? "✅ Si" : "❌ No"}\n` +
  73. `📯 *¿Es anuncio de comunidad?:* ${isCommunityAnnounce ? "✅" : "❌"}\n` +
  74. `🤝 *Tiene aprobación de miembros:* ${joinApprovalMode ? "✅" : "❌"}\n`
  75. return caption.trim()
  76. }
  77. let info
  78. try {
  79. let res = text ? null : await conn.groupMetadata(m.chat)
  80. info = await MetadataGroupInfo(res) // Si el bot esta en el grupo
  81. console.log('Método de metadatos')
  82. } catch {
  83. const inviteUrl = text?.match(/(?:https:\/\/)?(?:www\.)?(?:chat\.|wa\.)?whatsapp\.com\/(?:invite\/|joinchat\/)?([0-9A-Za-z]{22,24})/i)?.[1]
  84. //if (!inviteUrl &&) return await conn.reply(m.chat, "*Verifique que sea un enlace de grupo o comunidad de WhatsApp.*", m)
  85. let inviteInfo
  86. if (inviteUrl) {
  87. try {
  88. inviteInfo = await conn.groupGetInviteInfo(inviteUrl)
  89. info = await inviteGroupInfo(inviteInfo) // Para cualquier enlace de grupo/comunidad
  90. console.log(info)
  91. console.log('Método de enlace')
  92. } catch (e) {
  93. m.reply('Grupo no encontrado')
  94. return
  95. }}}
  96. if (info) {
  97. await conn.sendMessage(m.chat, { text: info, contextInfo: {
  98. mentionedJid: conn.parseMention(info),
  99. externalAdReply: {
  100. title: "🔰 Inspector de Grupos",
  101. body: packname,
  102. thumbnailUrl: pp ? pp : thumb,
  103. sourceUrl: args[0] ? args[0] : inviteCode ? `https://chat.whatsapp.com/${inviteCode}` : md,
  104. mediaType: 1,
  105. showAdAttribution: false,
  106. renderLargerThumbnail: false
  107. }}}, { quoted: fkontak })
  108. } else {
  109. // Manejo de enlaces de canales
  110. let newsletterInfo
  111. if (!channelUrl) return await conn.reply(m.chat, "*Verifique que sea un enlace de canal de WhatsApp.*", m)
  112. if (channelUrl) {
  113. try {
  114. newsletterInfo = await conn.newsletterMetadata("invite", channelUrl).catch(e => { return null })
  115. if (!newsletterInfo) return await conn.reply(m.chat, "*No se encontró información del canal.* Verifique que el enlace sea correcto.", m)
  116. let caption = "*Inspector de enlaces de Canales*\n\n" + processObject(newsletterInfo, "", newsletterInfo?.preview)
  117. if (newsletterInfo?.preview) {
  118. pp = getUrlFromDirectPath(newsletterInfo.preview)
  119. } else {
  120. pp = thumb
  121. }
  122. if (channelUrl && newsletterInfo) {
  123. await conn.sendMessage(m.chat, { text: caption, contextInfo: {
  124. mentionedJid: conn.parseMention(caption),
  125. externalAdReply: {
  126. title: "📢 Inspector de Canales",
  127. body: packname,
  128. thumbnailUrl: pp,
  129. sourceUrl: args[0],
  130. mediaType: 1,
  131. showAdAttribution: false,
  132. renderLargerThumbnail: false
  133. }}}, { quoted: fkontak })}
  134. newsletterInfo.id ? conn.sendMessage(m.chat, { text: newsletterInfo.id }, { quoted: null }) : ''
  135. } catch (e) {
  136. reportError(e)
  137. }}}}
  138. handler.help = ["superinspect", "inspect"]
  139. handler.tags = ['tools'];
  140. handler.command = /^(superinspect|inspect|revisar|inspeccionar)$/i;
  141. handler.register = true;
  142. export default handler;
  143. function formatDate(n, locale = "es", includeTime = true) {
  144. if (n > 1e12) {
  145. n = Math.floor(n / 1000) // Convertir de milisegundos a segundos
  146. } else if (n < 1e10) {
  147. n = Math.floor(n * 1000) // Convertir de segundos a milisegundos
  148. }
  149. const date = new Date(n)
  150. if (isNaN(date)) return "Fecha no válida"
  151. // Formato de fecha: día/mes/año
  152. const optionsDate = { day: '2-digit', month: '2-digit', year: 'numeric' }
  153. const formattedDate = date.toLocaleDateString(locale, optionsDate)
  154. if (!includeTime) return formattedDate
  155. // horas, minutos y segundos
  156. const hours = String(date.getHours()).padStart(2, '0')
  157. const minutes = String(date.getMinutes()).padStart(2, '0')
  158. const seconds = String(date.getSeconds()).padStart(2, '0')
  159. const period = hours < 12 ? 'AM' : 'PM'
  160. const formattedTime = `${hours}:${minutes}:${seconds} ${period}`
  161. return `${formattedDate}, ${formattedTime}`
  162. }
  163. function formatValue(key, value, preview) {
  164. switch (key) {
  165. case "subscribers":
  166. return value ? value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".") : "No hay suscriptores"
  167. case "creation_time":
  168. case "nameTime":
  169. case "descriptionTime":
  170. return formatDate(value)
  171. case "description":
  172. case "name":
  173. return value || "No hay información disponible"
  174. case "state":
  175. switch (value) {
  176. case "ACTIVE": return "Activo"
  177. case "GEOSUSPENDED": return "Suspendido por región"
  178. case "SUSPENDED": return "Suspendido"
  179. default: return "Desconocido"
  180. }
  181. case "reaction_codes":
  182. switch (value) {
  183. case "ALL": return "Todas las reacciones permitidas"
  184. case "BASIC": return "Reacciones básicas permitidas"
  185. case "NONE": return "No se permiten reacciones"
  186. default: return "Desconocido"
  187. }
  188. case "verification":
  189. switch (value) {
  190. case "VERIFIED": return "Verificado"
  191. case "UNVERIFIED": return "No verificado"
  192. default: return "Desconocido"
  193. }
  194. case "mute":
  195. switch (value) {
  196. case "ON": return "Silenciado"
  197. case "OFF": return "No silenciado"
  198. case "UNDEFINED": return "Sin definir"
  199. default: return "Desconocido"
  200. }
  201. case "view_role":
  202. switch (value) {
  203. case "ADMIN": return "Administrador"
  204. case "OWNER": return "Propietario"
  205. case "SUBSCRIBER": return "Suscriptor"
  206. case "GUEST": return "Invitado"
  207. default: return "Desconocido"
  208. }
  209. case "picture":
  210. if (preview) {
  211. return getUrlFromDirectPath(preview)
  212. } else {
  213. return "No hay imagen disponible"
  214. }
  215. default:
  216. return value !== null && value !== undefined ? value.toString() : "No hay información disponible"
  217. }}
  218. function newsletterKey(key) {
  219. return _.startCase(key.replace(/_/g, " "))
  220. .replace("Id", "🆔 Identificador")
  221. .replace("State", "📌 Estado")
  222. .replace("Creation Time", "📅 Fecha de creación")
  223. .replace("Name Time", "✏️ Fecha de modificación del nombre")
  224. .replace("Name", "🏷️ Nombre")
  225. .replace("Description Time", "📝 Fecha de modificación de la descripción")
  226. .replace("Description", "📜 Descripción")
  227. .replace("Invite", "📩 Invitación")
  228. .replace("Handle", "👤 Alias")
  229. .replace("Picture", "🖼️ Imagen")
  230. .replace("Preview", "👀 Vista previa")
  231. .replace("Reaction Codes", "😃 Reacciones")
  232. .replace("Subscribers", "👥 Suscriptores")
  233. .replace("Verification", "✅ Verificación")
  234. .replace("Viewer Metadata", "🔍 Datos avanzados")
  235. }
  236. function processObject(obj, prefix = "", preview) {
  237. let caption = ""
  238. Object.keys(obj).forEach(key => {
  239. const value = obj[key]
  240. if (typeof value === "object" && value !== null) {
  241. if (Object.keys(value).length > 0) {
  242. const sectionName = newsletterKey(prefix + key)
  243. caption += `\n*\`${sectionName}\`*\n`
  244. caption += processObject(value, `${prefix}${key}_`)
  245. }} else {
  246. const shortKey = prefix ? prefix.split("_").pop() + "_" + key : key
  247. const displayValue = formatValue(shortKey, value, preview)
  248. const translatedKey = newsletterKey(shortKey)
  249. caption += `- *${translatedKey}:*\n${displayValue}\n\n`
  250. }})
  251. return caption.trim()
  252. }