#!/usr/bin/env node /** * Script para scrapear documentación de Baileys relacionada con Media Messaging * Genera: baileys-media-messaging.md */ const BASE_URL = 'https://baileys.wiki/docs/api'; // Elementos a scrapear para media messaging const ELEMENTS = { typeAliases: [ 'AnyMediaMessageContent', 'AnyMessageContent', 'AnyRegularMessageContent', 'WAContactMessage', 'WAContactsArrayMessage', 'WALocationMessage', 'WAGenericMediaMessage', 'PollMessageOptions', 'EventMessageOptions', 'MediaType', 'MediaGenerationOptions', 'MiscMessageGenerationOptions', 'MessageGenerationOptions', 'MessageContentGenerationOptions', 'WAMediaUpload', 'DownloadableMessage', 'WAContextInfo', 'MessageWithContextInfo', ], functions: [ 'prepareWAMessageMedia', 'generateWAMessage', 'generateWAMessageContent', 'generateWAMessageFromContent', 'getContentType', 'extensionForMediaMessage', 'downloadMediaMessage', 'downloadContentFromMessage', 'encryptedStream', 'getMediaKeys', ], variables: [ 'MEDIA_KEYS', 'MEDIA_PATH_MAP', 'MEDIA_HKDF_KEY_MAPPING', ], interfaces: [ 'WAUrlInfo', ] }; // Función para hacer fetch con retry async function fetchWithRetry(url, retries = 3) { for (let i = 0; i < retries; i++) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return await response.text(); } catch (error) { console.error(` Intento ${i + 1}/${retries} fallido: ${error.message}`); if (i === retries - 1) throw error; await new Promise(r => setTimeout(r, 1000 * (i + 1))); } } } // Función para extraer contenido principal de una página function extractContent(html, elementName) { // Remover scripts, styles, nav, footer let content = html .replace(/]*>[\s\S]*?<\/script>/gi, '') .replace(/]*>[\s\S]*?<\/style>/gi, '') .replace(/]*>[\s\S]*?<\/nav>/gi, '') .replace(/]*>[\s\S]*?<\/footer>/gi, '') .replace(/]*>[\s\S]*?<\/header>/gi, ''); // Buscar el contenido principal (article o main) const articleMatch = content.match(/]*>([\s\S]*?)<\/article>/i); const mainMatch = content.match(/]*>([\s\S]*?)<\/main>/i); content = articleMatch ? articleMatch[1] : (mainMatch ? mainMatch[1] : content); // Convertir HTML a texto/markdown básico content = content // Headers .replace(/]*>([\s\S]*?)<\/h1>/gi, '\n# $1\n') .replace(/]*>([\s\S]*?)<\/h2>/gi, '\n## $1\n') .replace(/]*>([\s\S]*?)<\/h3>/gi, '\n### $1\n') .replace(/]*>([\s\S]*?)<\/h4>/gi, '\n#### $1\n') // Code blocks .replace(/]*>]*>([\s\S]*?)<\/code><\/pre>/gi, '\n```typescript\n$1\n```\n') .replace(/]*>([\s\S]*?)<\/code>/gi, '`$1`') // Lists .replace(/]*>([\s\S]*?)<\/li>/gi, '- $1\n') .replace(/]*>/gi, '\n') .replace(/<\/ul>/gi, '\n') .replace(/]*>/gi, '\n') .replace(/<\/ol>/gi, '\n') // Paragraphs .replace(/]*>([\s\S]*?)<\/p>/gi, '\n$1\n') // Bold/Italic .replace(/]*>([\s\S]*?)<\/strong>/gi, '**$1**') .replace(/]*>([\s\S]*?)<\/b>/gi, '**$1**') .replace(/]*>([\s\S]*?)<\/em>/gi, '*$1*') .replace(/]*>([\s\S]*?)<\/i>/gi, '*$1*') // Links .replace(/]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi, '[$2]($1)') // Divs y spans .replace(/]*>/gi, '\n') .replace(/<\/div>/gi, '\n') .replace(/]*>/gi, '') .replace(/<\/span>/gi, '') // Breaks .replace(//gi, '\n') // Remover otros tags HTML .replace(/<[^>]+>/g, '') // Decodificar entidades HTML .replace(/</g, '<') .replace(/>/g, '>') .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, "'") .replace(/'/g, "'") .replace(/ /g, ' ') // Limpiar espacios múltiples .replace(/\n{3,}/g, '\n\n') .replace(/[ \t]+/g, ' ') .trim(); return content; } // Función para construir URL según el tipo function buildUrl(type, name) { const urlMap = { typeAliases: `${BASE_URL}/type-aliases/${name}`, functions: `${BASE_URL}/functions/${name}`, variables: `${BASE_URL}/variables/${name}`, interfaces: `${BASE_URL}/interfaces/${name}`, }; return urlMap[type]; } // Función principal async function main() { console.log('🚀 Iniciando scraping de documentación de Baileys para Media Messaging...\n'); const results = { typeAliases: [], functions: [], variables: [], interfaces: [], }; // Scrapear cada categoría for (const [category, elements] of Object.entries(ELEMENTS)) { console.log(`\n📁 Scrapeando ${category}...`); for (const element of elements) { const url = buildUrl(category, element); console.log(` 📄 ${element}...`); try { const html = await fetchWithRetry(url); const content = extractContent(html, element); results[category].push({ name: element, url: url, content: content, }); console.log(` ✅ ${element} - OK`); // Pequeña pausa para no saturar el servidor await new Promise(r => setTimeout(r, 500)); } catch (error) { console.log(` ❌ ${element} - Error: ${error.message}`); results[category].push({ name: element, url: url, content: `Error al obtener documentación: ${error.message}`, error: true, }); } } } // Generar markdown console.log('\n📝 Generando markdown...'); let markdown = `# Baileys Media Messaging API Documentation > Documentación auto-generada para el desarrollo de mensajes multimedia en WhatsApp Nucleo > Fuente: https://baileys.wiki > Generado: ${new Date().toISOString()} Esta documentación contiene la API de Baileys relevante para enviar diferentes tipos de mensajes multimedia: - Imágenes y Videos - Documentos - Audio y Notas de Voz - Contactos - Ubicación - Encuestas (Polls) - Eventos ## Tabla de Contenidos `; // Generar tabla de contenidos const categoryNames = { interfaces: 'Interfaces', typeAliases: 'Type Aliases', functions: 'Funciones', variables: 'Variables', }; for (const [category, items] of Object.entries(results)) { if (items.length > 0) { markdown += `### ${categoryNames[category]}\n`; for (const item of items) { const anchor = `${category.slice(0, -1)}-${item.name.toLowerCase()}`; markdown += `- [${item.name}](#${anchor})\n`; } markdown += '\n'; } } // Agregar contenido de cada categoría for (const [category, items] of Object.entries(results)) { if (items.length > 0) { markdown += `\n---\n\n# ${categoryNames[category]}\n\n`; for (const item of items) { const typeLabel = category.slice(0, -1).replace(/([A-Z])/g, ' $1').trim(); markdown += `---\n\n## ${typeLabel}: ${item.name}\n\n`; markdown += `**Fuente:** ${item.url}\n\n`; if (item.error) { markdown += `> ⚠️ ${item.content}\n\n`; } else { markdown += `${item.content}\n\n`; } } } } // Agregar sección de ejemplos de uso markdown += ` --- # Ejemplos de Uso Comunes ## Enviar Imagen \`\`\`typescript import { prepareWAMessageMedia, generateWAMessageFromContent } from '@whiskeysockets/baileys' // Opción 1: Usando sendMessage directamente await sock.sendMessage(jid, { image: { url: './image.jpg' }, // o Buffer caption: 'Descripción de la imagen', mimetype: 'image/jpeg' }) // Opción 2: Con prepareWAMessageMedia const media = await prepareWAMessageMedia( { image: { url: './image.jpg' } }, { upload: sock.waUploadToServer } ) \`\`\` ## Enviar Video \`\`\`typescript await sock.sendMessage(jid, { video: { url: './video.mp4' }, caption: 'Mi video', mimetype: 'video/mp4', gifPlayback: false // true para GIFs }) \`\`\` ## Enviar Documento \`\`\`typescript await sock.sendMessage(jid, { document: { url: './document.pdf' }, mimetype: 'application/pdf', fileName: 'documento.pdf', caption: 'Documento importante' }) \`\`\` ## Enviar Audio \`\`\`typescript // Audio normal await sock.sendMessage(jid, { audio: { url: './audio.mp3' }, mimetype: 'audio/mp4' }) // Nota de voz (PTT) await sock.sendMessage(jid, { audio: { url: './voice.ogg' }, mimetype: 'audio/ogg; codecs=opus', ptt: true // Push To Talk = nota de voz }) \`\`\` ## Enviar Contacto \`\`\`typescript // Un contacto await sock.sendMessage(jid, { contacts: { displayName: 'Juan Pérez', contacts: [{ vcard: \`BEGIN:VCARD VERSION:3.0 FN:Juan Pérez TEL;type=CELL;waid=1234567890:+1234567890 END:VCARD\` }] } }) // Múltiples contactos await sock.sendMessage(jid, { contacts: { displayName: 'Mis Contactos', contacts: [ { vcard: '...' }, { vcard: '...' } ] } }) \`\`\` ## Enviar Ubicación \`\`\`typescript await sock.sendMessage(jid, { location: { degreesLatitude: 24.121231, degreesLongitude: 55.1121221 } }) \`\`\` ## Enviar Encuesta (Poll) \`\`\`typescript await sock.sendMessage(jid, { poll: { name: '¿Cuál es tu color favorito?', values: ['Rojo', 'Azul', 'Verde', 'Amarillo'], selectableCount: 1 // Cantidad de opciones seleccionables } }) \`\`\` ## Enviar con Quoted (Respuesta) \`\`\`typescript // El 'quoted' debe ser el mensaje original completo await sock.sendMessage(jid, { text: 'Esta es una respuesta' }, { quoted: originalMessage } ) // También funciona con media await sock.sendMessage(jid, { image: { url: './image.jpg' }, caption: 'Respuesta con imagen' }, { quoted: originalMessage } ) \`\`\` `; // Guardar archivo const fs = await import('fs'); const outputPath = './docs/baileys-media-messaging.md'; fs.writeFileSync(outputPath, markdown); console.log(`\n✅ Documentación generada exitosamente en: ${outputPath}`); console.log(` Total elementos: ${Object.values(results).flat().length}`); console.log(` - Type Aliases: ${results.typeAliases.length}`); console.log(` - Functions: ${results.functions.length}`); console.log(` - Variables: ${results.variables.length}`); console.log(` - Interfaces: ${results.interfaces.length}`); } main().catch(console.error);