discord-transcripts
Version:
A nicely formatted html transcript generator for discord.js.
411 lines (410 loc) • 27.3 kB
JavaScript
;
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(/\<\;a:(.+?):(\d+?)\>\;/g, function (_content, _name, id) { return "<img src=\"https://cdn.discordapp.com/emojis/".concat(id, ".gif?size=96\" class=\"emoji ").concat(emojiClass, "\">"); })
.replace(/\<\;:(.+?):(\d+?)\>\;/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(/\<\;@!*&*([0-9]{16,20})\>\;/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(/\<\;#!*&*([0-9]{16,20})\>\;/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;