First upload

This commit is contained in:
samkintop
2026-02-17 21:49:58 -06:00
parent 29a13768f7
commit 6821424663
46 changed files with 3179 additions and 14 deletions

View File

@@ -0,0 +1,129 @@
#!/usr/bin/env node
/**
* Map batch tickets (TICKET: guild_channelId_suffix) to transcript channel messages.
*
* Connection:
* - Batch line: TICKET: 798321161082896395_1423340928588054621_indiffe → channelId = 1423340928588054621.
* - Transcript channel (🖥│transcripts): each message is an embed with "Ticket Name: indifferentketchup🍅-claimed-7235".
* - Embed does NOT include channel ID, so we match by (1) ticket name (when known) or (2) time: transcript posted when ticket closes.
*
* Usage:
* node scripts/map-batch-to-transcript.js list [limit] -- fetch transcript messages, output CSV (messageId, created, ticket_name)
* node scripts/map-batch-to-transcript.js find <channelId> -- find transcript message(s) likely for this ticket (by time window)
*
* Known mapping (from embed): 1423340928588054621 ↔ message 1423400708769579120 (Ticket: indifferentketchup🍅-claimed-7235).
*/
const path = require('path');
const fs = require('fs');
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 TRANSCRIPT_CHANNEL_ID = '1335424071227281520';
const METRICS_CSV = path.join(__dirname, '../../Discord Ticket Transcripts/transcript_metrics_per_ticket.csv');
function getTicketNameFromEmbed(emb) {
const f = emb.fields?.find((x) => x.name && x.name.toLowerCase().includes('ticket name'));
return f ? f.value.trim() : null;
}
async function fetchTranscriptMessages(client, limit = 100) {
const channel = await client.channels.fetch(TRANSCRIPT_CHANNEL_ID).catch(() => null);
if (!channel) return [];
const cap = Math.min(limit, 100); // Discord API max 100 per request
const messages = await channel.messages.fetch({ limit: cap });
const out = [];
for (const [, m] of messages) {
const emb = m.embeds?.[0];
const ticketName = emb ? getTicketNameFromEmbed(emb) : null;
out.push({
messageId: m.id,
created: m.createdAt ? m.createdAt.toISOString() : m.createdTimestamp,
createdTs: m.createdTimestamp,
ticketName: ticketName || '',
});
}
out.sort((a, b) => b.createdTs - a.createdTs);
return out;
}
function loadMetricsCsv() {
if (!fs.existsSync(METRICS_CSV)) return [];
const text = fs.readFileSync(METRICS_CSV, 'utf8');
const lines = text.split(/\r?\n/).filter((l) => l.trim());
const header = lines[0].split(',');
const ticketIdIdx = header.indexOf('ticket_id');
const lastTsIdx = header.indexOf('last_message_ts');
if (ticketIdIdx === -1 || lastTsIdx === -1) return [];
const rows = [];
for (let i = 1; i < lines.length; i++) {
const parts = lines[i].split(',');
const ticketId = parts[ticketIdIdx];
const lastTs = parseInt(parts[lastTsIdx], 10);
if (!ticketId || !ticketId.includes('_')) continue;
const channelId = ticketId.split('_')[1];
if (channelId && !isNaN(lastTs)) rows.push({ ticketId, channelId, last_message_ts: lastTs });
}
return rows;
}
async function main() {
const cmd = process.argv[2];
const arg = process.argv[3];
if (!TOKEN) {
console.error('No bot token');
process.exit(1);
}
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
});
await new Promise((resolve, reject) => {
client.once('ready', resolve);
client.login(TOKEN).catch(reject);
});
try {
if (cmd === 'list') {
const limit = Math.min(parseInt(arg, 10) || 100, 100);
const list = await fetchTranscriptMessages(client, limit);
console.log('transcript_message_id,created_iso,ticket_name');
list.forEach((r) => console.log([r.messageId, r.created, r.ticketName].map((c) => `"${String(c).replace(/"/g, '""')}"`).join(',')));
return;
}
if (cmd === 'find' && arg) {
const channelId = arg.trim();
const metrics = loadMetricsCsv();
const row = metrics.find((r) => r.channelId === channelId);
const closeTs = row ? row.last_message_ts : null;
const list = await fetchTranscriptMessages(client, 100);
const windowMs = 2 * 60 * 60 * 1000; // ±2 hours
const candidates = closeTs
? list.filter((r) => Math.abs(r.createdTs - closeTs) <= windowMs)
: list.slice(0, 20);
console.log('Batch ticket channelId:', channelId);
if (row) console.log('Ticket close time (last_message_ts):', closeTs, new Date(closeTs).toISOString());
console.log('Transcript channel messages (candidates by time or recent):');
candidates.forEach((r) => {
const delta = closeTs != null ? (r.createdTs - closeTs) / 60000 : null;
console.log(' ', r.messageId, r.created, r.ticketName || '(no name)', delta != null ? `delta ${delta.toFixed(0)} min` : '');
});
return;
}
console.log('Usage: node scripts/map-batch-to-transcript.js list [limit]');
console.log(' node scripts/map-batch-to-transcript.js find <channelId>');
} finally {
client.destroy();
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});