110 lines
4.1 KiB
JavaScript
110 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Export transcript channel messages with embed "Users in transcript" to JSONL.
|
|
* Each line: { message_id, created, ticket_name, ticket_owner_id, users: [{ id, count }], total }
|
|
* Usage: node scripts/export-transcript-embeds.js <channelId> [maxMessages] [outputPath]
|
|
* If outputPath is omitted, writes to stdout (redirect: node ... > transcript_embeds.jsonl).
|
|
* If outputPath is given, writes JSONL to that file (avoids dotenv/logs mixing with JSON).
|
|
*/
|
|
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 fs = require('fs');
|
|
const TOKEN = process.env.MEMBER_BOT_TOKEN || process.env.DISCORD_BOT_TOKEN;
|
|
const channelId = process.argv[2];
|
|
const maxMessages = parseInt(process.argv[3], 10) || 10000;
|
|
const outputPath = process.argv[4];
|
|
const PAGE = 100;
|
|
|
|
// Parse "Users in transcript" value: "5 - <@123> - name#0\n 4 - <@456> - ..."
|
|
function parseUsersInTranscript(value) {
|
|
const users = [];
|
|
let total = 0;
|
|
const lines = (value || '').split(/\n/).map((s) => s.trim()).filter(Boolean);
|
|
for (const line of lines) {
|
|
const match = line.match(/^(\d+)\s+-\s+<@!?(\d+)>/);
|
|
if (match) {
|
|
const count = parseInt(match[1], 10);
|
|
users.push({ id: match[2], count });
|
|
total += count;
|
|
}
|
|
}
|
|
return { users, total };
|
|
}
|
|
|
|
if (!TOKEN || !channelId) {
|
|
console.error('Usage: node scripts/export-transcript-embeds.js <channelId> [maxMessages]');
|
|
process.exit(1);
|
|
}
|
|
|
|
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);
|
|
}
|
|
if (outputPath) {
|
|
fs.writeFileSync(outputPath, '');
|
|
}
|
|
let totalScanned = 0;
|
|
let before = undefined;
|
|
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 usersField = emb.fields?.find((f) => f.name && f.name.toLowerCase().includes('users in transcript'));
|
|
if (!usersField?.value) continue;
|
|
const ticketNameField = emb.fields?.find((f) => f.name && f.name.toLowerCase().includes('ticket name'));
|
|
const ticketName = ticketNameField?.value?.trim() || '';
|
|
const ownerField = emb.fields?.find((f) => f.name && f.name.toLowerCase().includes('ticket owner'));
|
|
const ownerMatch = ownerField?.value?.match(/<@!?(\d+)>/);
|
|
const ticket_owner_id = ownerMatch ? ownerMatch[1] : null;
|
|
const { users, total } = parseUsersInTranscript(usersField.value);
|
|
if (users.length === 0 && !ticket_owner_id) continue;
|
|
const out = {
|
|
message_id: m.id,
|
|
created: m.createdAt.toISOString(),
|
|
ticket_name: ticketName,
|
|
ticket_owner_id: ticket_owner_id || undefined,
|
|
users,
|
|
total,
|
|
};
|
|
const line = JSON.stringify(out) + '\n';
|
|
if (outputPath) {
|
|
fs.appendFileSync(outputPath, line);
|
|
} else {
|
|
process.stdout.write(line);
|
|
}
|
|
}
|
|
}
|
|
const oldestMsg = messages.reduce((a, m) => (m.createdTimestamp < (a?.createdTimestamp ?? Infinity) ? m : a), null);
|
|
before = oldestMsg?.id;
|
|
if (messages.size < PAGE) break;
|
|
}
|
|
process.stderr.write('Scanned ' + totalScanned + ' messages\n');
|
|
} 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);
|
|
});
|