/** * ============================================ * πŸ“¦ extractor.js β€” Extractor Integrado v0.1+v0.2 * ============================================ * Zelin puede extraer datos del servidor cuando * necesita actualizar su conocimiento. * Combina la lΓ³gica de los bots v0.1 y v0.2. */ import { ChannelType, PermissionsBitField } from 'discord.js'; import * as db from './db.js'; import { sleep } from './utils.js'; // ── ExtracciΓ³n de informaciΓ³n del servidor ──────────────────────────────────── export async function extractServerInfo(guild) { return { id : guild.id, name : guild.name, description : guild.description, ownerId : guild.ownerId, memberCount : guild.memberCount, boostLevel : guild.premiumTier, boostCount : guild.premiumSubscriptionCount ?? 0, features : guild.features, createdAt : guild.createdAt.toISOString(), extractedAt : new Date().toISOString(), }; } // ── ExtracciΓ³n y sync de roles ──────────────────────────────────────────────── export async function syncAllRoles(guild) { let count = 0; for (const role of guild.roles.cache.values()) { await db.upsertRole(role); count++; } console.log(`[Extractor] ${count} roles sincronizados`); return count; } // ── ExtracciΓ³n y sync de canales ───────────────────────────────────────────── export async function syncAllChannels(guild) { let count = 0; for (const channel of guild.channels.cache.values()) { await db.upsertChannel(channel); count++; } console.log(`[Extractor] ${count} canales sincronizados`); return count; } // ── ExtracciΓ³n y sync de miembros ───────────────────────────────────────────── export async function syncAllMembers(guild, onProgress = null) { await guild.members.fetch(); const members = [...guild.members.cache.values()]; let count = 0; for (const member of members) { await db.upsertUser(member); const roleIds = [...member.roles.cache.keys()].filter(id => id !== guild.id); await db.syncUserRoles(member.id, roleIds); count++; if (onProgress && count % 50 === 0) { await onProgress(count, members.length); } await sleep(50); // Rate limit suave } console.log(`[Extractor] ${count} miembros sincronizados`); return count; } // ── ExtracciΓ³n de historial de mensajes de un canal ─────────────────────────── export async function extractChannelMessages(channel, limit = 10000) { let lastId = null; let total = 0; let hasMore = true; while (hasMore && total < limit) { const options = { limit: 100 }; if (lastId) options.before = lastId; let batch; try { batch = await channel.messages.fetch(options); } catch { break; } if (batch.size === 0) break; for (const message of batch.values()) { if (message.author.bot) continue; try { await db.saveMessage(message); total++; } catch { // Mensaje ya guardado o error, continuar } } lastId = batch.last()?.id; hasMore = batch.size === 100; await sleep(1200); // Rate limit Discord } return total; } // ── ExtracciΓ³n completa del servidor (para uso interno de Zelin) ────────────── export async function runFullExtraction(guild, notifyProgress) { console.log('[Extractor] Iniciando extracciΓ³n completa...'); const results = { members: 0, roles: 0, channels: 0, messages: 0 }; // Roles if (notifyProgress) await notifyProgress('🎭 Sincronizando roles...'); results.roles = await syncAllRoles(guild); // Canales if (notifyProgress) await notifyProgress('πŸ“ Sincronizando canales...'); results.channels = await syncAllChannels(guild); // Miembros if (notifyProgress) await notifyProgress('πŸ‘₯ Sincronizando miembros...'); results.members = await syncAllMembers(guild, async (done, total) => { if (notifyProgress) await notifyProgress(`πŸ‘₯ Miembros: ${done}/${total}`); }); // Mensajes (canales de texto pΓΊblicos, ΓΊltimos 5000) if (notifyProgress) await notifyProgress('πŸ’¬ Extrayendo mensajes recientes...'); const textChannels = [...guild.channels.cache.values()] .filter(c => c.type === ChannelType.GuildText); for (const channel of textChannels) { try { const count = await extractChannelMessages(channel, 5000); results.messages += count; } catch { // Canal sin permisos, continuar } } console.log('[Extractor] ExtracciΓ³n completa:', results); return results; }