Skip to content

Instantly share code, notes, and snippets.

@ajmas
Last active January 19, 2025 05:47
Show Gist options
  • Save ajmas/5119169b2a2bbe9d349aa8959985e9c4 to your computer and use it in GitHub Desktop.
Save ajmas/5119169b2a2bbe9d349aa8959985e9c4 to your computer and use it in GitHub Desktop.
Discord Forum Threads to HTML
import { AnyThreadChannel, Channel, ChannelType, Client, FetchedThreads, ForumChannel, ForumThreadChannel, IntentsBitField, Message, Partials, ThreadChannel } from "discord.js";
let client: Client;
let botToken = 'xxxxxxxxxx';
async function getClient (): Promise<Client<boolean>> {
if (!client && botToken) {
// eslint-disable-next-line no-async-promise-executor
client = await new Promise(async (resolve, reject) => {
const intents: number[] = [
IntentsBitField.Flags.Guilds,
IntentsBitField.Flags.GuildMembers,
IntentsBitField.Flags.GuildEmojisAndStickers,
IntentsBitField.Flags.GuildMessages,
IntentsBitField.Flags.GuildPresences,
IntentsBitField.Flags.MessageContent,
IntentsBitField.Flags.DirectMessages,
IntentsBitField.Flags.DirectMessageTyping
];
const partials: Partials[] = [
Partials.Channel,
Partials.Message
];
const client = new Client({
intents,
partials
});
client.on('error', async (error) => {
reject(error);
});
client.on('ready', async () => {
resolve(client);
});
await client.login(botToken);
});
}
return client;
}
function messageToJson (message: Message): Record<string, unknown> {
const messageObj: Record<string, unknown> = {};
messageObj.id = message.id;
messageObj.content = message.content;
messageObj.author = message.author.username;
messageObj.createdAt = message.createdAt;
messageObj.attachments = message.attachments;
return messageObj;
}
async function threadToJson (thread: AnyThreadChannel, channel: ForumChannel): Promise<Record<string, unknown>> {
const threadObj: Record<string, unknown> = {};
threadObj.id = thread.id;
threadObj.name = thread.name;
threadObj.tags = thread.appliedTags.map(appliedTag => channel.availableTags.find(tag => tag.id == appliedTag)).map(tag => tag?.name);
threadObj.archived = thread.archived;
threadObj.archivedAt = thread.archivedAt;
threadObj.createdAt = thread.createdAt;
threadObj.messages = [];
const messages = await thread.messages.fetch({ cache: true, limit: 100 });
messages.forEach(message => {
(threadObj.messages as Record<string, unknown>[]).push(messageToJson(message));
});
return threadObj;
}
async function threadsToJson (threads: AnyThreadChannel[], channel: ForumChannel) {
let threadObjs: Record<string, unknown>[] = [];
for (let i = 0; i < threads.length; i++) {
threadObjs.push(await threadToJson(threads[i], channel));
}
return threadObjs;
}
async function listForumThreads (channelId: string, since?: Date) {
const client = await getClient();
const channel = client.channels.cache.get(channelId) as Channel;
let allThreads: Record<string, unknown>[] = [];
if (channel?.type === ChannelType.GuildForum) {
console.log('Channel:', channel.name);
console.log('Topic:', channel.topic);
let threadCache: FetchedThreads;
let threads: Record<string, unknown>[];
threadCache= await channel.threads.fetchActive(true);
threads = await threadsToJson(Array.from(threadCache.threads.entries()).map(entry => entry[1]), channel);
allThreads = [ ...allThreads, ...threads ];
threadCache = await channel.threads.fetchArchived({ fetchAll: true });
threads = await threadsToJson(Array.from(threadCache.threads.entries()).map(entry => entry[1]), channel);
allThreads = [ ...allThreads, ...threads ];
}
let html: string = '';
html = '<!DOCTYPE html><html>';
html += '<head>';
html += `
<style>
body {
font-family: sans-serif;
}
thread {
display: block;
border: solid 1px black;
margin: 7px;
padding: 14px;
}
ul.tags {
list-style: none;
display: flex;
gap: 16px;
padding: 0;
}
ul.tags li {
border: solid 1px black;
border-radius: 7px;
// background: blue;
padding: 2px 5px;
}
ul.messages {
list-style: none;
display: flex;
flex-direction: column;
gap: 14px;
padding: 0;
}
ul.messages li {
border: solid 1px grey;
padding: 7px;
}
</style>
`;
html += '</head>';
html += '<body>';
for (let i = 0; i < allThreads.length; i++) {
html += `<thread title="${allThreads[i].name}">`;
html += `<h3>${allThreads[i].name}</h3>`;
html += '<ul class="tags">';
(allThreads[i].tags as string[]).forEach(tag => html += `<li>${tag}</li>`);
// ${allThreads[i].tags}
html += '</ul>';
html += '<ul class="messages">';
const messages = allThreads[i].messages as Record<string, unknown>[];
for (let j = messages.length - 1; j >= 0; j--) {
html += '<li createdat="">';
html += `<pre>${messages[j].content}</pre>`
html += '</li>\n';
}
html += '</ul>\n';
html += '</thread>\n';
}
html += '</body></html>';
console.log(html);
process.exit(1);
}
listForumThreads('xxxxxxx').catch(error => console.log(error));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment