zelin-bot / src /extractor.js
Z User
v5.8.5: Gemma 4, MC Wiki, MC Player, anti-hallucination, CPU optimizations
ee826ee
/**
* ============================================
* πŸ“¦ 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;
}