Describe what you changed
This commit is contained in:
@@ -1,237 +1,237 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Discord user lookup WITH ROLES
|
||||
*
|
||||
* Fetches:
|
||||
* - User info (username, display name, avatar)
|
||||
* - Guild member info (roles, join date, server nickname)
|
||||
* - All Palpocalypse server roles
|
||||
*
|
||||
* Requires: Server Members Intent enabled in Discord Developer Portal
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Client, GatewayIntentBits } = require('discord.js');
|
||||
|
||||
require('dotenv').config({ path: path.join(__dirname, '../../.env') });
|
||||
|
||||
const TOKEN = process.env.MEMBER_BOT_TOKEN || process.env.DISCORD_BOT_TOKEN;
|
||||
const GUILD_ID = '798321161082896395'; // Indifferent Broccoli server
|
||||
|
||||
if (!TOKEN) {
|
||||
console.error('❌ Error: No bot token found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length < 2) {
|
||||
console.error('Usage: node scripts/lookup-with-roles.js <input_file> <output_file>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const inputFile = args[0];
|
||||
const outputFile = args[1];
|
||||
|
||||
const userIds = fs.readFileSync(inputFile, 'utf-8')
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.length > 0);
|
||||
|
||||
console.log(`✅ Loaded ${userIds.length} user IDs`);
|
||||
|
||||
let results = {};
|
||||
let processed = 0;
|
||||
let errors = 0;
|
||||
|
||||
if (fs.existsSync(outputFile)) {
|
||||
try {
|
||||
const existing = JSON.parse(fs.readFileSync(outputFile, 'utf-8'));
|
||||
results = existing.users || {};
|
||||
processed = Object.keys(results).length;
|
||||
errors = existing.errors || 0;
|
||||
console.log(`📂 Found existing: ${processed} users`);
|
||||
} catch (e) {
|
||||
console.log(`⚠️ Starting fresh`);
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMembers // Required for roles!
|
||||
]
|
||||
});
|
||||
|
||||
let guild = null;
|
||||
|
||||
async function lookupUserWithRoles(userId) {
|
||||
if (results[userId]) return results[userId];
|
||||
|
||||
try {
|
||||
// Fetch basic user info
|
||||
const user = await client.users.fetch(userId);
|
||||
|
||||
// Try to fetch guild member (for roles)
|
||||
let roles = [];
|
||||
let serverNickname = null;
|
||||
let joinedAt = null;
|
||||
let isInServer = false;
|
||||
|
||||
try {
|
||||
const member = await guild.members.fetch(userId);
|
||||
isInServer = true;
|
||||
serverNickname = member.nickname;
|
||||
joinedAt = member.joinedAt ? member.joinedAt.toISOString() : null;
|
||||
|
||||
// Get all roles except @everyone
|
||||
roles = member.roles.cache
|
||||
.filter(role => role.name !== '@everyone')
|
||||
.map(role => ({
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
color: role.hexColor,
|
||||
position: role.position
|
||||
}))
|
||||
.sort((a, b) => b.position - a.position); // Highest role first
|
||||
|
||||
} catch (memberError) {
|
||||
// User exists but not in this server
|
||||
isInServer = false;
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
globalName: user.globalName || user.username,
|
||||
tag: user.tag,
|
||||
bot: user.bot,
|
||||
avatar: user.displayAvatarURL(),
|
||||
// Server-specific data
|
||||
server_nickname: serverNickname,
|
||||
joined_at: joinedAt,
|
||||
in_server: isInServer,
|
||||
roles: roles,
|
||||
role_names: roles.map(r => r.name),
|
||||
highest_role: roles[0]?.name || null
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
id: userId,
|
||||
error: error.message,
|
||||
username: null,
|
||||
globalName: null,
|
||||
roles: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function saveResults() {
|
||||
const output = {
|
||||
timestamp: new Date().toISOString(),
|
||||
total_users: userIds.length,
|
||||
processed: processed,
|
||||
successful: processed - errors,
|
||||
errors: errors,
|
||||
guild_id: GUILD_ID,
|
||||
includes_roles: true,
|
||||
users: results
|
||||
};
|
||||
|
||||
fs.writeFileSync(outputFile, JSON.stringify(output, null, 2));
|
||||
}
|
||||
|
||||
async function processUsers() {
|
||||
console.log('\n🎭 Starting lookups WITH ROLES...');
|
||||
console.log(` Guild ID: ${GUILD_ID}`);
|
||||
console.log(` Rate: 1 user/second\n`);
|
||||
|
||||
// Fetch guild
|
||||
guild = await client.guilds.fetch(GUILD_ID);
|
||||
console.log(`✅ Connected to: ${guild.name}\n`);
|
||||
|
||||
const startTime = Date.now();
|
||||
const toProcess = userIds.filter(id => !results[id]);
|
||||
console.log(` ${toProcess.length} users remaining\n`);
|
||||
|
||||
for (let i = 0; i < toProcess.length; i++) {
|
||||
const userId = toProcess[i];
|
||||
|
||||
const result = await lookupUserWithRoles(userId);
|
||||
results[result.id] = result;
|
||||
|
||||
if (!result.success) errors++;
|
||||
processed++;
|
||||
|
||||
// Save every 10 users
|
||||
if (processed % 10 === 0) {
|
||||
saveResults();
|
||||
const elapsed = (Date.now() - startTime) / 1000;
|
||||
const rate = (processed - (userIds.length - toProcess.length)) / elapsed;
|
||||
const remaining = (toProcess.length - i - 1) / rate;
|
||||
|
||||
// Show sample with roles
|
||||
if (result.success && result.roles.length > 0) {
|
||||
const rolePreview = result.role_names.slice(0, 2).join(', ');
|
||||
console.log(`💾 ${processed}/${userIds.length} - ${result.globalName} [${rolePreview}] - ~${remaining.toFixed(0)}s left`);
|
||||
} else {
|
||||
console.log(`💾 ${processed}/${userIds.length} (${errors} errors) - ~${remaining.toFixed(0)}s left`);
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
saveResults();
|
||||
|
||||
const totalTime = (Date.now() - startTime) / 1000;
|
||||
|
||||
// Stats
|
||||
const usersWithRoles = Object.values(results).filter(u => u.success && u.roles.length > 0).length;
|
||||
const allRoleNames = new Set();
|
||||
Object.values(results).forEach(u => {
|
||||
if (u.success) {
|
||||
u.role_names?.forEach(r => allRoleNames.add(r));
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\n${'='.repeat(70)}`);
|
||||
console.log(`✅ Complete with Roles!`);
|
||||
console.log(`${'='.repeat(70)}`);
|
||||
console.log(` Time: ${totalTime.toFixed(1)}s`);
|
||||
console.log(` Processed: ${processed}/${userIds.length}`);
|
||||
console.log(` Successful: ${processed - errors}`);
|
||||
console.log(` Users with roles: ${usersWithRoles}`);
|
||||
console.log(` Unique roles found: ${allRoleNames.size}`);
|
||||
console.log(`\n💾 Saved to: ${outputFile}\n`);
|
||||
|
||||
// Show some roles
|
||||
if (allRoleNames.size > 0) {
|
||||
console.log('📋 Sample roles found:');
|
||||
Array.from(allRoleNames).slice(0, 10).forEach(r => console.log(` • ${r}`));
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
client.once('ready', () => {
|
||||
console.log(`✅ Logged in as ${client.user.tag}\n`);
|
||||
processUsers();
|
||||
});
|
||||
|
||||
client.on('error', (error) => {
|
||||
console.error('❌ Error:', error.message);
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n\n⚠️ Interrupted! Saving...');
|
||||
saveResults();
|
||||
console.log('✅ Saved. Resume by running same command.\n');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
console.log('🔌 Connecting to Discord...');
|
||||
client.login(TOKEN);
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Discord user lookup WITH ROLES
|
||||
*
|
||||
* Fetches:
|
||||
* - User info (username, display name, avatar)
|
||||
* - Guild member info (roles, join date, server nickname)
|
||||
* - All Palpocalypse server roles
|
||||
*
|
||||
* Requires: Server Members Intent enabled in Discord Developer Portal
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Client, GatewayIntentBits } = require('discord.js');
|
||||
|
||||
require('dotenv').config({ path: path.join(__dirname, '../../.env') });
|
||||
|
||||
const TOKEN = process.env.MEMBER_BOT_TOKEN || process.env.DISCORD_BOT_TOKEN;
|
||||
const GUILD_ID = '798321161082896395'; // Indifferent Broccoli server
|
||||
|
||||
if (!TOKEN) {
|
||||
console.error('❌ Error: No bot token found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length < 2) {
|
||||
console.error('Usage: node scripts/lookup-with-roles.js <input_file> <output_file>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const inputFile = args[0];
|
||||
const outputFile = args[1];
|
||||
|
||||
const userIds = fs.readFileSync(inputFile, 'utf-8')
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.length > 0);
|
||||
|
||||
console.log(`✅ Loaded ${userIds.length} user IDs`);
|
||||
|
||||
let results = {};
|
||||
let processed = 0;
|
||||
let errors = 0;
|
||||
|
||||
if (fs.existsSync(outputFile)) {
|
||||
try {
|
||||
const existing = JSON.parse(fs.readFileSync(outputFile, 'utf-8'));
|
||||
results = existing.users || {};
|
||||
processed = Object.keys(results).length;
|
||||
errors = existing.errors || 0;
|
||||
console.log(`📂 Found existing: ${processed} users`);
|
||||
} catch (e) {
|
||||
console.log(`⚠️ Starting fresh`);
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMembers // Required for roles!
|
||||
]
|
||||
});
|
||||
|
||||
let guild = null;
|
||||
|
||||
async function lookupUserWithRoles(userId) {
|
||||
if (results[userId]) return results[userId];
|
||||
|
||||
try {
|
||||
// Fetch basic user info
|
||||
const user = await client.users.fetch(userId);
|
||||
|
||||
// Try to fetch guild member (for roles)
|
||||
let roles = [];
|
||||
let serverNickname = null;
|
||||
let joinedAt = null;
|
||||
let isInServer = false;
|
||||
|
||||
try {
|
||||
const member = await guild.members.fetch(userId);
|
||||
isInServer = true;
|
||||
serverNickname = member.nickname;
|
||||
joinedAt = member.joinedAt ? member.joinedAt.toISOString() : null;
|
||||
|
||||
// Get all roles except @everyone
|
||||
roles = member.roles.cache
|
||||
.filter(role => role.name !== '@everyone')
|
||||
.map(role => ({
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
color: role.hexColor,
|
||||
position: role.position
|
||||
}))
|
||||
.sort((a, b) => b.position - a.position); // Highest role first
|
||||
|
||||
} catch (memberError) {
|
||||
// User exists but not in this server
|
||||
isInServer = false;
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
globalName: user.globalName || user.username,
|
||||
tag: user.tag,
|
||||
bot: user.bot,
|
||||
avatar: user.displayAvatarURL(),
|
||||
// Server-specific data
|
||||
server_nickname: serverNickname,
|
||||
joined_at: joinedAt,
|
||||
in_server: isInServer,
|
||||
roles: roles,
|
||||
role_names: roles.map(r => r.name),
|
||||
highest_role: roles[0]?.name || null
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
id: userId,
|
||||
error: error.message,
|
||||
username: null,
|
||||
globalName: null,
|
||||
roles: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function saveResults() {
|
||||
const output = {
|
||||
timestamp: new Date().toISOString(),
|
||||
total_users: userIds.length,
|
||||
processed: processed,
|
||||
successful: processed - errors,
|
||||
errors: errors,
|
||||
guild_id: GUILD_ID,
|
||||
includes_roles: true,
|
||||
users: results
|
||||
};
|
||||
|
||||
fs.writeFileSync(outputFile, JSON.stringify(output, null, 2));
|
||||
}
|
||||
|
||||
async function processUsers() {
|
||||
console.log('\n🎭 Starting lookups WITH ROLES...');
|
||||
console.log(` Guild ID: ${GUILD_ID}`);
|
||||
console.log(` Rate: 1 user/second\n`);
|
||||
|
||||
// Fetch guild
|
||||
guild = await client.guilds.fetch(GUILD_ID);
|
||||
console.log(`✅ Connected to: ${guild.name}\n`);
|
||||
|
||||
const startTime = Date.now();
|
||||
const toProcess = userIds.filter(id => !results[id]);
|
||||
console.log(` ${toProcess.length} users remaining\n`);
|
||||
|
||||
for (let i = 0; i < toProcess.length; i++) {
|
||||
const userId = toProcess[i];
|
||||
|
||||
const result = await lookupUserWithRoles(userId);
|
||||
results[result.id] = result;
|
||||
|
||||
if (!result.success) errors++;
|
||||
processed++;
|
||||
|
||||
// Save every 10 users
|
||||
if (processed % 10 === 0) {
|
||||
saveResults();
|
||||
const elapsed = (Date.now() - startTime) / 1000;
|
||||
const rate = (processed - (userIds.length - toProcess.length)) / elapsed;
|
||||
const remaining = (toProcess.length - i - 1) / rate;
|
||||
|
||||
// Show sample with roles
|
||||
if (result.success && result.roles.length > 0) {
|
||||
const rolePreview = result.role_names.slice(0, 2).join(', ');
|
||||
console.log(`💾 ${processed}/${userIds.length} - ${result.globalName} [${rolePreview}] - ~${remaining.toFixed(0)}s left`);
|
||||
} else {
|
||||
console.log(`💾 ${processed}/${userIds.length} (${errors} errors) - ~${remaining.toFixed(0)}s left`);
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
saveResults();
|
||||
|
||||
const totalTime = (Date.now() - startTime) / 1000;
|
||||
|
||||
// Stats
|
||||
const usersWithRoles = Object.values(results).filter(u => u.success && u.roles.length > 0).length;
|
||||
const allRoleNames = new Set();
|
||||
Object.values(results).forEach(u => {
|
||||
if (u.success) {
|
||||
u.role_names?.forEach(r => allRoleNames.add(r));
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\n${'='.repeat(70)}`);
|
||||
console.log(`✅ Complete with Roles!`);
|
||||
console.log(`${'='.repeat(70)}`);
|
||||
console.log(` Time: ${totalTime.toFixed(1)}s`);
|
||||
console.log(` Processed: ${processed}/${userIds.length}`);
|
||||
console.log(` Successful: ${processed - errors}`);
|
||||
console.log(` Users with roles: ${usersWithRoles}`);
|
||||
console.log(` Unique roles found: ${allRoleNames.size}`);
|
||||
console.log(`\n💾 Saved to: ${outputFile}\n`);
|
||||
|
||||
// Show some roles
|
||||
if (allRoleNames.size > 0) {
|
||||
console.log('📋 Sample roles found:');
|
||||
Array.from(allRoleNames).slice(0, 10).forEach(r => console.log(` • ${r}`));
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
client.once('ready', () => {
|
||||
console.log(`✅ Logged in as ${client.user.tag}\n`);
|
||||
processUsers();
|
||||
});
|
||||
|
||||
client.on('error', (error) => {
|
||||
console.error('❌ Error:', error.message);
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\n\n⚠️ Interrupted! Saving...');
|
||||
saveResults();
|
||||
console.log('✅ Saved. Resume by running same command.\n');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
console.log('🔌 Connecting to Discord...');
|
||||
client.login(TOKEN);
|
||||
|
||||
Reference in New Issue
Block a user