Last active
January 19, 2025 05:47
-
-
Save ajmas/5119169b2a2bbe9d349aa8959985e9c4 to your computer and use it in GitHub Desktop.
Discord Forum Threads to HTML
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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