Sélectionner une révision Git
messageprocessor.ts 4,36 Kio
import * as Discord from "discord.js";
import * as marked from "marked";
import * as log from "npmlog";
import { DiscordBot } from "./bot";
import * as escapeStringRegexp from "escape-string-regexp";
const USER_REGEX = /<@!?([0-9]*)>/g;
const CHANNEL_REGEX = /<#?([0-9]*)>/g;
const EMOJI_SIZE = "1em";
const EMOJI_REGEX = /<:\w+:?([0-9]*)>/g;
const MATRIX_TO_LINK = "https://matrix.to/#/";
marked.setOptions({
sanitize: true,
});
export class MessageProcessorOpts {
public domain: string;
constructor (domain: string) {
this.domain = domain;
}
}
export class MessageProcessorMatrixResult {
public formattedBody: string;
public body: string;
}
export class MessageProcessor {
private readonly opts: MessageProcessorOpts;
private readonly bot: DiscordBot;
constructor (opts: MessageProcessorOpts, bot: DiscordBot) {
this.opts = opts;
this.bot = bot;
}
public async FormatDiscordMessage(msg: Discord.Message): Promise<MessageProcessorMatrixResult> {
const result = new MessageProcessorMatrixResult();
// Replace embeds.
let content = msg.content;
content = this.InsertEmbeds(content, msg);
// Replace Users
content = this.ReplaceMembers(content, msg);
content = this.ReplaceChannels(content, msg);
content = await this.ReplaceEmoji(content, msg);
// Replace channels
result.body = content;
result.formattedBody = marked(content);
return result;
}
public InsertEmbeds(content: string, msg: Discord.Message): string {
for (const embed of msg.embeds) {
let embedContent = "\n\n----"; // Horizontal rule. Two to make sure the content doesn't become a title.
const embedTitle = embed.url ? `[${embed.title}](${embed.url})` : embed.title;
if (embedTitle) {
embedContent += "\n##### " + embedTitle; // h5 is probably best.
}
if (embed.description) {
embedContent += "\n" + embed.description;
}
content += embedContent;
}
return content;
}
public ReplaceMembers(content: string, msg: Discord.Message): string {
let results = USER_REGEX.exec(content);
while (results !== null) {
const id = results[1];
const member = msg.guild.members.get(id);
const memberId = `@_discord_${id}:${this.opts.domain}`;
const memberStr = member ? member.user.username : memberId;
content = content.replace(results[0], memberStr);
results = USER_REGEX.exec(content);
}
return content;
}
public ReplaceChannels(content: string, msg: Discord.Message): string {
let results = CHANNEL_REGEX.exec(content);
while (results !== null) {
const id = results[1];
const channel = msg.guild.channels.get(id);
const roomId = `#_discord_${msg.guild.id}_${id}:${this.opts.domain}`;
const channelStr = channel ? "#" + channel.name : "#" + id;
content = content.replace(results[0], `[${channelStr}](${MATRIX_TO_LINK}${roomId})`);
results = CHANNEL_REGEX.exec(content);
}
return content;
}
public async ReplaceEmoji(content: string, msg: Discord.Message): Promise<string> {
let results = EMOJI_REGEX.exec(content);
while (results !== null) {
const id = results[1];
try {
const mxcUrl = await this.bot.GetGuildEmoji(msg.guild, id);
content = content.replace(results[0],
`<img alt="${id}" src="${mxcUrl}" style="height: ${EMOJI_SIZE};"/>`);
} catch (ex) {
log.warn("MessageProcessor",
`Could not insert emoji ${id} for msg ${msg.id} in guild ${msg.guild.id}: ${ex}`,
);
}
results = EMOJI_REGEX.exec(content);
}
return content;
}
public FindMentionsInPlainBody(body: string, members: Discord.GuildMember[]): string {
for (const member of members) {
const matcher = escapeStringRegexp(member.user.username + "#" + member.user.discriminator) + "|" +
escapeStringRegexp(member.displayName);
body = body.replace(
new RegExp(
`\\b(${matcher})(?=\\b)`
, "mig"), `<@!${member.id}>`,
);
}
return body;
}
}