UNPKG

discord-transcripts

Version:

A nicely formatted html transcript generator for discord.js.

411 lines (410 loc) 27.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var discord = require("discord.js"); var jsdom_1 = require("jsdom"); var fs = require("fs"); var path = require("path"); var he = require("he"); var highlight_js_1 = require("highlight.js"); var staticTypes = require("./static"); var template = fs.readFileSync(path.join(__dirname, 'template.html'), 'utf8'); // copilot helped so much here // copilot smart 🧠 function generateTranscript(messages, channel, opts) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y; if (opts === void 0) { opts = { returnBuffer: false, fileName: 'transcript.html' }; } if (channel.type === "DM") throw new Error("Cannot operate on DM channels"); var dom = new jsdom_1.JSDOM(template.replace('{{TITLE}}', channel.name)); var document = dom.window.document; // const xss = new XSS.FilterXSS({ // whiteList: staticTypes.xssSettings // }).process; // Basic Info (header) var guildIcon = document.getElementsByClassName('preamble__guild-icon')[0]; guildIcon.src = (_a = channel.guild.iconURL()) !== null && _a !== void 0 ? _a : staticTypes.defaultPFP; document.getElementById('guildname').textContent = channel.guild.name; document.getElementById('ticketname').textContent = channel.name; var transcript = document.getElementById('chatlog'); var _loop_1 = function (message) { // create message group var messageGroup = document.createElement('div'); messageGroup.classList.add('chatlog__message-group'); // message reference if ((_b = message.reference) === null || _b === void 0 ? void 0 : _b.messageId) { // create symbol var referenceSymbol = document.createElement('div'); referenceSymbol.classList.add('chatlog__reference-symbol'); // create reference var reference = document.createElement('div'); reference.classList.add('chatlog__reference'); var referencedMessage = messages instanceof discord.Collection ? messages.get(message.reference.messageId) : messages.find(function (m) { return m.id === message.reference.messageId; }); var author_1 = (_c = referencedMessage === null || referencedMessage === void 0 ? void 0 : referencedMessage.author) !== null && _c !== void 0 ? _c : staticTypes.DummyUser; reference.innerHTML = "<img class=\"chatlog__reference-avatar\" src=\"".concat((_d = author_1.avatarURL({ dynamic: true })) !== null && _d !== void 0 ? _d : staticTypes.defaultPFP, "\" alt=\"Avatar\" loading=\"lazy\">\n <span class=\"chatlog__reference-name\" title=\"").concat(author_1.username.replace(/"/g, ''), "\" style=\"color: ").concat((_e = author_1.hexAccentColor) !== null && _e !== void 0 ? _e : '#FFFFFF', "\">").concat(author_1.bot ? "<span class=\"chatlog__bot-tag\">BOT</span> ".concat(he.escape(author_1.username)) : he.escape(author_1.username), "</span>\n <div class=\"chatlog__reference-content\">\n <span class=\"chatlog__reference-link\" onclick=\"scrollToMessage(event, '").concat(message.reference.messageId, "')\">\n ").concat(referencedMessage ? ((referencedMessage === null || referencedMessage === void 0 ? void 0 : referencedMessage.content) ? "".concat(formatContent(referencedMessage === null || referencedMessage === void 0 ? void 0 : referencedMessage.content, channel, false, true), "...") : '<em>Click to see attachment</em>') : '<em>Original message was deleted.</em>', "\n </span>\n </div>"); messageGroup.appendChild(referenceSymbol); messageGroup.appendChild(reference); } // message author pfp var author = (_f = message.author) !== null && _f !== void 0 ? _f : staticTypes.DummyUser; var authorElement = document.createElement('div'); authorElement.classList.add('chatlog__author-avatar-container'); var authorAvatar = document.createElement('img'); authorAvatar.classList.add('chatlog__author-avatar'); authorAvatar.src = (_g = author.avatarURL({ dynamic: true })) !== null && _g !== void 0 ? _g : staticTypes.defaultPFP; authorAvatar.alt = 'Avatar'; authorAvatar.loading = 'lazy'; authorElement.appendChild(authorAvatar); messageGroup.appendChild(authorElement); // message content var content = document.createElement('div'); content.classList.add('chatlog__messages'); // message author name var authorName = document.createElement('span'); authorName.classList.add('chatlog__author-name'); authorName.title = he.escape(author.tag); authorName.textContent = author.username; authorName.setAttribute('data-user-id', author.id); content.appendChild(authorName); if (author.bot) { var botTag = document.createElement('span'); botTag.classList.add('chatlog__bot-tag'); botTag.textContent = 'BOT'; content.appendChild(botTag); } // timestamp var timestamp = document.createElement('span'); timestamp.classList.add('chatlog__timestamp'); timestamp.textContent = message.createdAt.toLocaleString(); content.appendChild(timestamp); var messageContent = document.createElement('div'); messageContent.classList.add('chatlog__message'); messageContent.setAttribute('data-message-id', message.id); messageContent.setAttribute('id', "message-".concat(message.id)); messageContent.title = "Message sent: ".concat(message.createdAt.toLocaleString()); // message content if (message.content) { var messageContentContent = document.createElement('div'); messageContentContent.classList.add('chatlog__content'); var messageContentContentMarkdown = document.createElement('div'); messageContentContentMarkdown.classList.add('markdown'); var messageContentContentMarkdownSpan = document.createElement('span'); messageContentContentMarkdownSpan.classList.add('preserve-whitespace'); messageContentContentMarkdownSpan.innerHTML = formatContent(message.content, channel, message.webhookId !== null); messageContentContentMarkdown.appendChild(messageContentContentMarkdownSpan); messageContentContent.appendChild(messageContentContentMarkdown); messageContent.appendChild(messageContentContent); } // message attachments if (message.attachments && message.attachments.size > 0) { for (var _0 = 0, _1 = Array.from(message.attachments.values()); _0 < _1.length; _0++) { var attachment = _1[_0]; var attachmentsDiv = document.createElement('div'); attachmentsDiv.classList.add('chatlog__attachment'); var attachmentType = ((_h = attachment.name) !== null && _h !== void 0 ? _h : "unknown.png").split('.').pop().toLowerCase(); if (['png', 'jpg', 'jpeg', 'gif'].includes(attachmentType)) { var attachmentLink = document.createElement('a'); var attachmentImage = document.createElement('img'); attachmentImage.classList.add('chatlog__attachment-media'); attachmentImage.src = (_j = attachment.proxyURL) !== null && _j !== void 0 ? _j : attachment.url; attachmentImage.alt = 'Image attachment'; attachmentImage.loading = 'lazy'; attachmentImage.title = "Image: ".concat(attachment.name, " (").concat(formatBytes(attachment.size), ")"); attachmentLink.appendChild(attachmentImage); attachmentsDiv.appendChild(attachmentLink); } else if (['mp4', 'webm'].includes(attachmentType)) { var attachmentVideo = document.createElement('video'); attachmentVideo.classList.add('chatlog__attachment-media'); attachmentVideo.src = (_k = attachment.proxyURL) !== null && _k !== void 0 ? _k : attachment.url; // attachmentVideo.alt = 'Video attachment'; attachmentVideo.controls = true; attachmentVideo.title = "Video: ".concat(attachment.name, " (").concat(formatBytes(attachment.size), ")"); attachmentsDiv.appendChild(attachmentVideo); } else if (['mp3', 'ogg'].includes(attachmentType)) { var attachmentAudio = document.createElement('audio'); attachmentAudio.classList.add('chatlog__attachment-media'); attachmentAudio.src = (_l = attachment.proxyURL) !== null && _l !== void 0 ? _l : attachment.url; // attachmentAudio.alt = 'Audio attachment'; attachmentAudio.controls = true; attachmentAudio.title = "Audio: ".concat(attachment.name, " (").concat(formatBytes(attachment.size), ")"); attachmentsDiv.appendChild(attachmentAudio); } else { var attachmentGeneric = document.createElement('div'); attachmentGeneric.classList.add('chatlog__attachment-generic'); var attachmentGenericIcon = document.createElement('svg'); attachmentGenericIcon.classList.add('chatlog__attachment-generic-icon'); var attachmentGenericIconUse = document.createElement('use'); attachmentGenericIconUse.setAttribute('href', '#icon-attachment'); attachmentGenericIcon.appendChild(attachmentGenericIconUse); attachmentGeneric.appendChild(attachmentGenericIcon); var attachmentGenericName = document.createElement('div'); attachmentGenericName.classList.add('chatlog__attachment-generic-name'); var attachmentGenericNameLink = document.createElement('a'); attachmentGenericNameLink.href = (_m = attachment.proxyURL) !== null && _m !== void 0 ? _m : attachment.url; attachmentGenericNameLink.textContent = attachment.name; attachmentGenericName.appendChild(attachmentGenericNameLink); attachmentGeneric.appendChild(attachmentGenericName); var attachmentGenericSize = document.createElement('div'); attachmentGenericSize.classList.add('chatlog__attachment-generic-size'); attachmentGenericSize.textContent = "".concat(formatBytes(attachment.size)); attachmentGeneric.appendChild(attachmentGenericSize); attachmentsDiv.appendChild(attachmentGeneric); } messageContent.appendChild(attachmentsDiv); } } content.appendChild(messageContent); // embeds if (message.embeds && message.embeds.length > 0) { var _loop_2 = function (embed) { var _4; var embedDiv = document.createElement('div'); embedDiv.classList.add('chatlog__embed'); // embed color if (embed.hexColor) { var embedColorPill = document.createElement('div'); embedColorPill.classList.add('chatlog__embed-color-pill'); embedColorPill.style.backgroundColor = embed.hexColor; embedDiv.appendChild(embedColorPill); } var embedContentContainer = document.createElement('div'); embedContentContainer.classList.add('chatlog__embed-content-container'); var embedContent = document.createElement('div'); embedContent.classList.add('chatlog__embed-content'); var embedText = document.createElement('div'); embedText.classList.add('chatlog__embed-text'); // embed author if ((_o = embed.author) === null || _o === void 0 ? void 0 : _o.name) { var embedAuthor = document.createElement('div'); embedAuthor.classList.add('chatlog__embed-author'); if (embed.author.iconURL) { var embedAuthorIcon_1 = document.createElement('img'); embedAuthorIcon_1.classList.add('chatlog__embed-author-icon'); embedAuthorIcon_1.src = embed.author.iconURL; embedAuthorIcon_1.alt = 'Author icon'; embedAuthorIcon_1.loading = 'lazy'; embedAuthorIcon_1.onerror = function () { return embedAuthorIcon_1.style.visibility = 'hidden'; }; embedAuthor.appendChild(embedAuthorIcon_1); } var embedAuthorName = document.createElement('span'); embedAuthorName.classList.add('chatlog__embed-author-name'); if (embed.author.url) { var embedAuthorNameLink = document.createElement('a'); embedAuthorNameLink.classList.add('chatlog__embed-author-name-link'); embedAuthorNameLink.href = embed.author.url; embedAuthorNameLink.textContent = embed.author.name; embedAuthorName.appendChild(embedAuthorNameLink); } else { embedAuthorName.textContent = embed.author.name; } embedAuthor.appendChild(embedAuthorName); embedText.appendChild(embedAuthor); } // embed title if (embed.title) { var embedTitle = document.createElement('div'); embedTitle.classList.add('chatlog__embed-title'); if (embed.url) { var embedTitleLink = document.createElement('a'); embedTitleLink.classList.add('chatlog__embed-title-link'); embedTitleLink.href = embed.url; var embedTitleMarkdown = document.createElement('div'); embedTitleMarkdown.classList.add('markdown', 'preserve-whitespace'); embedTitleMarkdown.textContent = embed.title; embedTitleLink.appendChild(embedTitleMarkdown); embedTitle.appendChild(embedTitleLink); } else { var embedTitleMarkdown = document.createElement('div'); embedTitleMarkdown.classList.add('markdown', 'preserve-whitespace'); embedTitleMarkdown.textContent = embed.title; embedTitle.appendChild(embedTitleMarkdown); } embedText.appendChild(embedTitle); } // embed description if (embed.description) { var embedDescription = document.createElement('div'); embedDescription.classList.add('chatlog__embed-description'); var embedDescriptionMarkdown = document.createElement('div'); embedDescriptionMarkdown.classList.add('markdown', 'preserve-whitespace'); embedDescriptionMarkdown.innerHTML = formatContent(embed.description, channel, true); embedDescription.appendChild(embedDescriptionMarkdown); embedText.appendChild(embedDescription); } // embed fields if (embed.fields && embed.fields.length > 0) { var embedFields = document.createElement('div'); embedFields.classList.add('chatlog__embed-fields'); for (var _5 = 0, _6 = embed.fields; _5 < _6.length; _5++) { var field = _6[_5]; var embedField = document.createElement('div'); (_4 = embedField.classList).add.apply(_4, (!field.inline ? ['chatlog__embed-field'] : ['chatlog__embed-field', 'chatlog__embed-field--inline'])); // Field name var embedFieldName = document.createElement('div'); embedFieldName.classList.add('chatlog__embed-field-name'); var embedFieldNameMarkdown = document.createElement('div'); embedFieldNameMarkdown.classList.add('markdown', 'preserve-whitespace'); embedFieldNameMarkdown.textContent = field.name; embedFieldName.appendChild(embedFieldNameMarkdown); embedField.appendChild(embedFieldName); // Field value var embedFieldValue = document.createElement('div'); embedFieldValue.classList.add('chatlog__embed-field-value'); var embedFieldValueMarkdown = document.createElement('div'); embedFieldValueMarkdown.classList.add('markdown', 'preserve-whitespace'); embedFieldValueMarkdown.innerHTML = formatContent(field.value, channel, true); embedFieldValue.appendChild(embedFieldValueMarkdown); embedField.appendChild(embedFieldValue); embedFields.appendChild(embedField); } embedText.appendChild(embedFields); } embedContent.appendChild(embedText); // embed thumbnail if ((_q = (_p = embed.thumbnail) === null || _p === void 0 ? void 0 : _p.proxyURL) !== null && _q !== void 0 ? _q : (_r = embed.thumbnail) === null || _r === void 0 ? void 0 : _r.url) { var embedThumbnail = document.createElement('div'); embedThumbnail.classList.add('chatlog__embed-thumbnail-container'); var embedThumbnailLink = document.createElement('a'); embedThumbnailLink.classList.add('chatlog__embed-thumbnail-link'); embedThumbnailLink.href = (_s = embed.thumbnail.proxyURL) !== null && _s !== void 0 ? _s : embed.thumbnail.url; var embedThumbnailImage = document.createElement('img'); embedThumbnailImage.classList.add('chatlog__embed-thumbnail'); embedThumbnailImage.src = (_t = embed.thumbnail.proxyURL) !== null && _t !== void 0 ? _t : embed.thumbnail.url; embedThumbnailImage.alt = 'Thumbnail'; embedThumbnailImage.loading = 'lazy'; embedThumbnailLink.appendChild(embedThumbnailImage); embedThumbnail.appendChild(embedThumbnailLink); embedContent.appendChild(embedThumbnail); } embedContentContainer.appendChild(embedContent); // embed image if (embed.image) { var embedImage = document.createElement('div'); embedImage.classList.add('chatlog__embed-image-container'); var embedImageLink = document.createElement('a'); embedImageLink.classList.add('chatlog__embed-image-link'); embedImageLink.href = (_u = embed.image.proxyURL) !== null && _u !== void 0 ? _u : embed.image.url; var embedImageImage = document.createElement('img'); embedImageImage.classList.add('chatlog__embed-image'); embedImageImage.src = (_v = embed.image.proxyURL) !== null && _v !== void 0 ? _v : embed.image.url; embedImageImage.alt = 'Image'; embedImageImage.loading = 'lazy'; embedImageLink.appendChild(embedImageImage); embedImage.appendChild(embedImageLink); embedContentContainer.appendChild(embedImage); } // footer if ((_w = embed.footer) === null || _w === void 0 ? void 0 : _w.text) { var embedFooter = document.createElement('div'); embedFooter.classList.add('chatlog__embed-footer'); if (embed.footer.iconURL) { var embedFooterIcon = document.createElement('img'); embedFooterIcon.classList.add('chatlog__embed-footer-icon'); embedFooterIcon.src = (_x = embed.footer.proxyIconURL) !== null && _x !== void 0 ? _x : embed.footer.iconURL; embedFooterIcon.alt = 'Footer icon'; embedFooterIcon.loading = 'lazy'; embedFooter.appendChild(embedFooterIcon); } var embedFooterText = document.createElement('span'); embedFooterText.classList.add('chatlog__embed-footer-text'); embedFooterText.textContent = embed.timestamp ? "".concat(embed.footer.text, " \u2022 ").concat(new Date(embed.timestamp).toLocaleString()) : embed.footer.text; embedFooter.appendChild(embedFooterText); embedContentContainer.appendChild(embedFooter); } embedDiv.appendChild(embedContentContainer); content.appendChild(embedDiv); }; for (var _2 = 0, _3 = message.embeds; _2 < _3.length; _2++) { var embed = _3[_2]; _loop_2(embed); } } messageGroup.appendChild(content); transcript.appendChild(messageGroup); }; // Messages for (var _i = 0, _z = (Array.from(messages.values())).sort(function (a, b) { return a.createdTimestamp - b.createdTimestamp; }); _i < _z.length; _i++) { var message = _z[_i]; _loop_1(message); } return opts.returnBuffer ? Buffer.from(dom.serialize()) : new discord.MessageAttachment(Buffer.from(dom.serialize()), (_y = opts.fileName) !== null && _y !== void 0 ? _y : 'transcript.html'); } var languages = highlight_js_1.default.listLanguages(); function formatContent(content, context, allowExtra, replyStyle, purify) { if (allowExtra === void 0) { allowExtra = false; } if (replyStyle === void 0) { replyStyle = false; } if (purify === void 0) { purify = he.escape; } var emojiClass = /^(<(a?):([^:]+?):(\d+?)>([ \t]+?)?){0,27}$/.test(content) ? "emoji--large" : "emoji--small"; content = purify(content) .replace(/\&\#x60;/g, '`') // we dont want ` to be escaped .replace(/```(.+?)```/gs, function (code) { var _a; if (!replyStyle) { var split = code.slice(3, -3).split('\n'); var language = ((_a = split.shift()) !== null && _a !== void 0 ? _a : "").trim().toLowerCase(); if (language in staticTypes.LanguageAliases) language = staticTypes.LanguageAliases[language]; if (languages.includes(language)) { var joined = he.unescape(split.join("\n")); return "<div class=\"pre pre--multiline language-".concat(language, "\">").concat(highlight_js_1.default.highlight(joined, { language: language, }).value, "</div>"); } else { return "<div class=\"pre pre--multiline nohighlight\">".concat(code .slice(3, -3) .trim(), "</div>"); } } else { var split = code.slice(3, -3).split('\n'); split.shift(); var joined = he.unescape(split.join('\n')); return "<span class=\"pre pre--inline\">".concat(joined.substring(0, 42), "</span>"); } }) .replace(/\&lt\;a:(.+?):(\d+?)\&gt\;/g, function (_content, _name, id) { return "<img src=\"https://cdn.discordapp.com/emojis/".concat(id, ".gif?size=96\" class=\"emoji ").concat(emojiClass, "\">"); }) .replace(/\&lt\;:(.+?):(\d+?)\&gt\;/g, function (_content, _name, id) { return "<img src=\"https://cdn.discordapp.com/emojis/".concat(id, ".webp?size=96\" class=\"emoji ").concat(emojiClass, "\">"); }) .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>') .replace(/\*(.+?)\*/g, '<em>$1</em>') .replace(/~~(.+?)~~/g, '<s>$1</s>') .replace(/__(.+?)__/g, '<u>$1</u>') .replace(/\_(.+?)\_/g, '<em>$1</em>') .replace(/`(.+?)`/g, "<span class=\"pre pre--inline\">$1</span>") .replace(/\|\|(.+?)\|\|/g, "<span class=\"spoiler-text spoiler-text--hidden\" ".concat(replyStyle ? '' : 'onclick="showSpoiler(event, this)"', ">$1</span>")) .replace(/\&lt\;@!*&*([0-9]{16,20})\&gt\;/g, function (user) { var _a, _b, _c, _d, _e; var userId = ((_a = user.match(/[0-9]{16,20}/)) !== null && _a !== void 0 ? _a : [""])[0]; var userInGuild = (_c = (_b = context.client) === null || _b === void 0 ? void 0 : _b.users) === null || _c === void 0 ? void 0 : _c.resolve(userId); return "<span class=\"mention\" title=\"".concat((_d = userInGuild === null || userInGuild === void 0 ? void 0 : userInGuild.tag) !== null && _d !== void 0 ? _d : userId, "\">@").concat((_e = userInGuild === null || userInGuild === void 0 ? void 0 : userInGuild.username) !== null && _e !== void 0 ? _e : "Unknown User", "</span>"); }) .replace(/\&lt\;#!*&*([0-9]{16,20})\&gt\;/g, function (channel) { var _a, _b, _c; var channelId = ((_a = channel.match(/[0-9]{16,20}/)) !== null && _a !== void 0 ? _a : [""])[0]; var channelInGuild = context.guild.channels.resolve(channelId); var pre = channelInGuild ? channelInGuild.isText() ? '#' : channelInGuild.isVoice() ? '🔊' : '📁' : "#"; return "<span class=\"mention\" title=\"".concat((_b = channelInGuild === null || channelInGuild === void 0 ? void 0 : channelInGuild.name) !== null && _b !== void 0 ? _b : channelId, "\">").concat(pre).concat((_c = channelInGuild === null || channelInGuild === void 0 ? void 0 : channelInGuild.name) !== null && _c !== void 0 ? _c : "Unknown Channel", "</span>"); }); if (allowExtra) { content = content .replace(/\[(.+?)\]\((.+?)\)/g, "<a href=\"$2\">$1</a>"); } return replyStyle ? content.replace(/(?:\r\n|\r|\n)/g, ' ') : content.replace(/(?:\r\n|\r|\n)/g, '<br />'); // do this last } function formatBytes(bytes, decimals) { if (decimals === void 0) { decimals = 2; } if (bytes === 0) return '0 Bytes'; var k = 1024; var dm = decimals < 0 ? 0 : decimals; var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } exports.default = generateTranscript;