#!/usr/bin/env node /** * Find transcript messages whose embed "Ticket Owner" is a given user ID. * Usage: node scripts/find-transcript-by-owner.js [totalMessages] [maxMessages] * If totalMessages is given, only show messages where "Users in transcript" sum equals that. * Example: node scripts/find-transcript-by-owner.js 1335424071227281520 241129484483297280 5 10000 */ const path = require('path'); const { Client, GatewayIntentBits } = require('discord.js'); require('dotenv').config({ path: path.join(__dirname, '../.env') }); require('dotenv').config({ path: path.join(__dirname, '../../.env') }); const TOKEN = process.env.MEMBER_BOT_TOKEN || process.env.DISCORD_BOT_TOKEN; const channelId = process.argv[2]; const ownerId = process.argv[3]; const totalMessages = parseInt(process.argv[4], 10) || null; const maxMessages = parseInt(process.argv[5], 10) || 10000; const PAGE = 100; function parseUsersTotal(value) { let total = 0; (value || '').split(/\n/).forEach((line) => { const m = line.trim().match(/^(\d+)\s+-\s+<@!?\d+>/); if (m) total += parseInt(m[1], 10); }); return total; } if (!TOKEN || !channelId || !ownerId) { console.error('Usage: node scripts/find-transcript-by-owner.js [totalMessages] [maxMessages]'); process.exit(1); } const ownerRef = `<@${ownerId}>`; const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages], }); client.once('ready', async () => { try { const channel = await client.channels.fetch(channelId).catch(() => null); if (!channel) { console.error('Channel not found or bot cannot access it.'); process.exit(1); } console.error('Channel:', channel.name, '(' + channel.id + ')'); console.error('Looking for Ticket Owner', ownerId, totalMessages != null ? 'and total=' + totalMessages : ''); let totalScanned = 0; let before = undefined; let found = 0; while (totalScanned < maxMessages) { const limit = Math.min(PAGE, maxMessages - totalScanned); const options = before ? { limit, before } : { limit }; const messages = await channel.messages.fetch(options); if (messages.size === 0) break; totalScanned += messages.size; for (const [, m] of messages.sort((a, b) => b.createdTimestamp - a.createdTimestamp)) { if (!m.embeds?.length) continue; for (const emb of m.embeds) { const ownerField = emb.fields?.find((f) => f.name && f.name.toLowerCase().includes('ticket owner')); if (!ownerField?.value || !ownerField.value.includes(ownerRef)) continue; const usersField = emb.fields?.find((f) => f.name && f.name.toLowerCase().includes('users in transcript')); const total = usersField?.value ? parseUsersTotal(usersField.value) : 0; if (totalMessages != null && total !== totalMessages) continue; const ticketNameField = emb.fields?.find((f) => f.name && f.name.toLowerCase().includes('ticket name')); const ticketName = ticketNameField?.value?.trim() || ''; console.log('Message ID:', m.id); console.log('Created:', m.createdAt.toISOString()); console.log('Ticket Name:', ticketName); console.log('Total messages:', total); console.log('---'); found++; } } const oldestMsg = messages.reduce((a, msg) => (msg.createdTimestamp < (a?.createdTimestamp ?? Infinity) ? msg : a), null); before = oldestMsg?.id; if (messages.size < PAGE) break; } console.error('Scanned', totalScanned, 'messages, matches:', found); } catch (e) { console.error(e.message || e); } finally { client.destroy(); process.exit(0); } }); client.login(TOKEN).catch((e) => { console.error('Login failed:', e.message); process.exit(1); });