Fix: Corregir UModal en MessageContact usando v-model:open
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
El modal de contacto usaba v-model en lugar de v-model:open según la documentación de Nuxt UI 4. También se actualizó la estructura para usar los slots correctos del UModal (#header, #body, #footer).
This commit is contained in:
1117
docs/baileys-media-messaging.md
Normal file
1117
docs/baileys-media-messaging.md
Normal file
File diff suppressed because it is too large
Load Diff
400
docs/scrape-media-docs.mjs
Normal file
400
docs/scrape-media-docs.mjs
Normal file
@@ -0,0 +1,400 @@
|
||||
#!/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(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
||||
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
|
||||
.replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, '')
|
||||
.replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, '')
|
||||
.replace(/<header[^>]*>[\s\S]*?<\/header>/gi, '');
|
||||
|
||||
// Buscar el contenido principal (article o main)
|
||||
const articleMatch = content.match(/<article[^>]*>([\s\S]*?)<\/article>/i);
|
||||
const mainMatch = content.match(/<main[^>]*>([\s\S]*?)<\/main>/i);
|
||||
|
||||
content = articleMatch ? articleMatch[1] : (mainMatch ? mainMatch[1] : content);
|
||||
|
||||
// Convertir HTML a texto/markdown básico
|
||||
content = content
|
||||
// Headers
|
||||
.replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, '\n# $1\n')
|
||||
.replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, '\n## $1\n')
|
||||
.replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, '\n### $1\n')
|
||||
.replace(/<h4[^>]*>([\s\S]*?)<\/h4>/gi, '\n#### $1\n')
|
||||
// Code blocks
|
||||
.replace(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/gi, '\n```typescript\n$1\n```\n')
|
||||
.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, '`$1`')
|
||||
// Lists
|
||||
.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, '- $1\n')
|
||||
.replace(/<ul[^>]*>/gi, '\n')
|
||||
.replace(/<\/ul>/gi, '\n')
|
||||
.replace(/<ol[^>]*>/gi, '\n')
|
||||
.replace(/<\/ol>/gi, '\n')
|
||||
// Paragraphs
|
||||
.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, '\n$1\n')
|
||||
// Bold/Italic
|
||||
.replace(/<strong[^>]*>([\s\S]*?)<\/strong>/gi, '**$1**')
|
||||
.replace(/<b[^>]*>([\s\S]*?)<\/b>/gi, '**$1**')
|
||||
.replace(/<em[^>]*>([\s\S]*?)<\/em>/gi, '*$1*')
|
||||
.replace(/<i[^>]*>([\s\S]*?)<\/i>/gi, '*$1*')
|
||||
// Links
|
||||
.replace(/<a[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi, '[$2]($1)')
|
||||
// Divs y spans
|
||||
.replace(/<div[^>]*>/gi, '\n')
|
||||
.replace(/<\/div>/gi, '\n')
|
||||
.replace(/<span[^>]*>/gi, '')
|
||||
.replace(/<\/span>/gi, '')
|
||||
// Breaks
|
||||
.replace(/<br\s*\/?>/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);
|
||||
Reference in New Issue
Block a user