Spaces:
Paused
Paused
| /** | |
| * ============================================ | |
| * π¦ 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; | |
| } | |