From 676cab0dc8c2fc7d32b6fad31a5b4cb4bdb88779 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Fri, 13 Feb 2026 20:27:25 +1300 Subject: [PATCH 1/2] Use smalltext for interaction header --- src/d2m/converters/message-to-event.js | 36 +++++++-- .../message-to-event.test.embeds.js | 77 ++++++++----------- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/d2m/converters/message-to-event.js b/src/d2m/converters/message-to-event.js index 6109b0f..8f7d0ee 100644 --- a/src/d2m/converters/message-to-event.js +++ b/src/d2m/converters/message-to-event.js @@ -247,6 +247,20 @@ async function pollToEvent(poll) { } } +/** + * @param {DiscordTypes.APIMessageInteraction} interaction + * @param {boolean} isThinkingInteraction + */ +function getFormattedInteraction(interaction, isThinkingInteraction) { + const mxid = select("sim", "mxid", {user_id: interaction.user.id}).pluck().get() + const username = interaction.member?.nick || interaction.user.global_name || interaction.user.username + const thinkingText = isThinkingInteraction ? " — interaction loading..." : "" + return { + body: `↪️ ${username} used \`/${interaction.name}\`${thinkingText}`, + html: `
↪️ ${mxid ? tag`${username}` : username} used /${interaction.name}${thinkingText}
` + } +} + /** * @param {DiscordTypes.APIMessage} message * @param {DiscordTypes.APIGuild} guild @@ -321,13 +335,8 @@ async function messageToEvent(message, guild, options = {}, di) { } const interaction = message.interaction_metadata || message.interaction - if (message.type === DiscordTypes.MessageType.ChatInputCommand && interaction && "name" in interaction) { - // Commands are sent by the responding bot. Need to attach the metadata of the person using the command at the top. - let content = message.content - if (content) content = `\n${content}` - else if ((message.flags || 0) & DiscordTypes.MessageFlags.Loading) content = " — interaction loading..." - message.content = `> ↪️ <@${interaction.user.id}> used \`/${interaction.name}\`${content}` - } + const isInteraction = message.type === DiscordTypes.MessageType.ChatInputCommand && !!interaction && "name" in interaction + const isThinkingInteraction = isInteraction && !!((message.flags || 0) & DiscordTypes.MessageFlags.Loading) /** @type {{room?: boolean, user_ids?: string[]}} @@ -621,6 +630,12 @@ async function messageToEvent(message, guild, options = {}, di) { } } + if (isInteraction && !isThinkingInteraction && events.length === 0) { + const formattedInteraction = getFormattedInteraction(interaction, false) + body = `${formattedInteraction.body}\n${body}` + html = `${formattedInteraction.html}${html}` + } + const newTextMessageEvent = { $type: "m.room.message", "m.mentions": mentions, @@ -712,8 +727,13 @@ async function messageToEvent(message, guild, options = {}, di) { events.push(...forwardedEvents) } + if (isThinkingInteraction) { + const formattedInteraction = getFormattedInteraction(interaction, true) + await addTextEvent(formattedInteraction.body, formattedInteraction.html, "m.notice") + } + // Then text content - if (message.content && !isOnlyKlipyGIF) { + if (message.content && !isOnlyKlipyGIF && !isThinkingInteraction) { // Mentions scenario 3: scan the message content for written @mentions of matrix users. Allows for up to one space between @ and mention. let content = message.content if (options.scanTextForMentions !== false) { diff --git a/src/d2m/converters/message-to-event.test.embeds.js b/src/d2m/converters/message-to-event.test.embeds.js index cfb2f96..259aa66 100644 --- a/src/d2m/converters/message-to-event.test.embeds.js +++ b/src/d2m/converters/message-to-event.test.embeds.js @@ -4,24 +4,31 @@ const data = require("../../../test/data") const {mockGetEffectivePower} = require("../../matrix/utils.test") const {db} = require("../../passthrough") +test("message2event embeds: interaction loading", async t => { + const events = await messageToEvent(data.interaction_message.thinking_interaction, data.guild.general, {}) + t.deepEqual(events, [{ + $type: "m.room.message", + body: "↪️ Brad used `/stats` — interaction loading...", + format: "org.matrix.custom.html", + formatted_body: "
↪️ Brad used /stats — interaction loading...
", + "m.mentions": {}, + msgtype: "m.notice", + }]) +}) + test("message2event embeds: nothing but a field", async t => { const events = await messageToEvent(data.message_with_embeds.nothing_but_a_field, data.guild.general, {}) t.deepEqual(events, [{ - $type: "m.room.message", - body: "> ↪️ @papiophidian: used `/stats`", - format: "org.matrix.custom.html", - formatted_body: "
↪️ @papiophidian used /stats
", - "m.mentions": {}, - msgtype: "m.text", - }, { $type: "m.room.message", "m.mentions": {}, msgtype: "m.notice", - body: "| ### Amanda 🎵#2192 :online:" + body: "↪️ PapiOphidian used `/stats`" + + "\n| ### Amanda 🎵#2192 :online:" + "\n| willow tree, branch 0" + "\n| **❯ Uptime:**\n| 3m 55s\n| **❯ Memory:**\n| 64.45MB", format: "org.matrix.custom.html", - formatted_body: '

Amanda 🎵#2192 \":online:\"' + formatted_body: '

↪️ PapiOphidian used /stats
' + + '

Amanda 🎵#2192 \":online:\"' + '
willow tree, branch 0
' + '
❯ Uptime:
3m 55s' + '
❯ Memory:
64.45MB

' @@ -144,18 +151,13 @@ test("message2event embeds: crazy html is all escaped", async t => { test("message2event embeds: title without url", async t => { const events = await messageToEvent(data.message_with_embeds.title_without_url, data.guild.general) t.deepEqual(events, [{ - $type: "m.room.message", - body: "> ↪️ @papiophidian: used `/stats`", - format: "org.matrix.custom.html", - formatted_body: "
↪️ @papiophidian used /stats
", - "m.mentions": {}, - msgtype: "m.text", - }, { $type: "m.room.message", msgtype: "m.notice", - body: "| ## Hi, I'm Amanda!\n| \n| I condone pirating music!", + body: "↪️ PapiOphidian used `/stats`" + + "\n| ## Hi, I'm Amanda!\n| \n| I condone pirating music!", format: "org.matrix.custom.html", - formatted_body: `

Hi, I'm Amanda!

I condone pirating music!

`, + formatted_body: '
↪️ PapiOphidian used /stats
' + + `

Hi, I'm Amanda!

I condone pirating music!

`, "m.mentions": {} }]) }) @@ -163,18 +165,13 @@ test("message2event embeds: title without url", async t => { test("message2event embeds: url without title", async t => { const events = await messageToEvent(data.message_with_embeds.url_without_title, data.guild.general) t.deepEqual(events, [{ - $type: "m.room.message", - body: "> ↪️ @papiophidian: used `/stats`", - format: "org.matrix.custom.html", - formatted_body: "
↪️ @papiophidian used /stats
", - "m.mentions": {}, - msgtype: "m.text", - }, { $type: "m.room.message", msgtype: "m.notice", - body: "| I condone pirating music!", + body: "↪️ PapiOphidian used `/stats`" + + "\n| I condone pirating music!", format: "org.matrix.custom.html", - formatted_body: `

I condone pirating music!

`, + formatted_body: '
↪️ PapiOphidian used /stats
' + + `

I condone pirating music!

`, "m.mentions": {} }]) }) @@ -182,18 +179,13 @@ test("message2event embeds: url without title", async t => { test("message2event embeds: author without url", async t => { const events = await messageToEvent(data.message_with_embeds.author_without_url, data.guild.general) t.deepEqual(events, [{ - $type: "m.room.message", - body: "> ↪️ @papiophidian: used `/stats`", - format: "org.matrix.custom.html", - formatted_body: "
↪️ @papiophidian used /stats
", - "m.mentions": {}, - msgtype: "m.text", - }, { $type: "m.room.message", msgtype: "m.notice", - body: "| ## Amanda\n| \n| I condone pirating music!", + body: "↪️ PapiOphidian used `/stats`" + + "\n| ## Amanda\n| \n| I condone pirating music!", format: "org.matrix.custom.html", - formatted_body: `

Amanda

I condone pirating music!

`, + formatted_body: '
↪️ PapiOphidian used /stats
' + + `

Amanda

I condone pirating music!

`, "m.mentions": {} }]) }) @@ -201,18 +193,13 @@ test("message2event embeds: author without url", async t => { test("message2event embeds: author url without name", async t => { const events = await messageToEvent(data.message_with_embeds.author_url_without_name, data.guild.general) t.deepEqual(events, [{ - $type: "m.room.message", - body: "> ↪️ @papiophidian: used `/stats`", - format: "org.matrix.custom.html", - formatted_body: "
↪️ @papiophidian used /stats
", - "m.mentions": {}, - msgtype: "m.text", - }, { $type: "m.room.message", msgtype: "m.notice", - body: "| I condone pirating music!", + body: "↪️ PapiOphidian used `/stats`" + + "\n| I condone pirating music!", format: "org.matrix.custom.html", - formatted_body: `

I condone pirating music!

`, + formatted_body: '
↪️ PapiOphidian used /stats
' + + `

I condone pirating music!

`, "m.mentions": {} }]) }) From 5002f3046a0b23f77405080f65f8e22c55269565 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Fri, 13 Feb 2026 20:27:38 +1300 Subject: [PATCH 2/2] Convert emojihax to real emoji --- src/d2m/converters/message-to-event.js | 5 ++++ src/d2m/converters/message-to-event.test.js | 12 ++++++++ test/data.js | 31 +++++++++++++++++++++ test/ooye-test-data.sql | 3 +- 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/d2m/converters/message-to-event.js b/src/d2m/converters/message-to-event.js index 8f7d0ee..7f77b81 100644 --- a/src/d2m/converters/message-to-event.js +++ b/src/d2m/converters/message-to-event.js @@ -757,6 +757,11 @@ async function messageToEvent(message, guild, options = {}, di) { } } + // Scan the content for emojihax and replace them with real emojis + content = content.replaceAll(/\[([a-zA-Z0-9_-]{2,32})(?:~[0-9]+)?\]\(https:\/\/cdn\.discordapp\.com\/emojis\/([0-9]+)\.[^ \n)`]+\)/g, (_, name, id) => { + return `<:${name}:${id}>` + }) + const {body, html} = await transformContent(content) await addTextEvent(body, html, msgtype) } diff --git a/src/d2m/converters/message-to-event.test.js b/src/d2m/converters/message-to-event.test.js index 84cc1e0..1a73aea 100644 --- a/src/d2m/converters/message-to-event.test.js +++ b/src/d2m/converters/message-to-event.test.js @@ -1171,6 +1171,18 @@ test("message2event: emoji that hasn't been registered yet", async t => { }]) }) +test("message2event: emojihax", async t => { + const events = await messageToEvent(data.message.emojihax, data.guild.general, {}) + t.deepEqual(events, [{ + $type: "m.room.message", + "m.mentions": {}, + msgtype: "m.text", + body: "I only violate the don't modify our console part of terms of service :troll:", + format: "org.matrix.custom.html", + formatted_body: `I only violate the don't modify our console part of terms of service :troll:` + }]) +}) + test("message2event: emoji triple long name", async t => { const events = await messageToEvent(data.message.emoji_triple_long_name, data.guild.general, {}) t.deepEqual(events, [{ diff --git a/test/data.js b/test/data.js index eef3a50..6a53cb0 100644 --- a/test/data.js +++ b/test/data.js @@ -3219,6 +3219,37 @@ module.exports = { flags: 0, components: [] }, + emojihax: { + id: "1126733830494093453", + type: 0, + content: "I only violate the don't modify our console part of terms of service [troll~1](https://cdn.discordapp.com/emojis/1254940125948022915.webp?size=48&name=troll%7E1&lossless=true)", + channel_id: "112760669178241024", + author: { + id: "111604486476181504", + username: "kyuugryphon", + avatar: "e4ce31267ca524d19be80e684d4cafa1", + discriminator: "0", + public_flags: 0, + flags: 0, + banner: null, + accent_color: null, + global_name: "KyuuGryphon", + avatar_decoration: null, + display_name: "KyuuGryphon", + banner_color: null + }, + attachments: [], + embeds: [], + mentions: [], + mention_roles: [], + pinned: false, + mention_everyone: false, + tts: false, + timestamp: "2023-07-07T04:37:58.892000+00:00", + edited_timestamp: null, + flags: 0, + components: [] + }, emoji_triple_long_name: { id: "1156394116540805170", type: 0, diff --git a/test/ooye-test-data.sql b/test/ooye-test-data.sql index 3df5901..1dd9dfe 100644 --- a/test/ooye-test-data.sql +++ b/test/ooye-test-data.sql @@ -152,7 +152,8 @@ INSERT INTO file (discord_url, mxc_url) VALUES ('https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg', 'mxc://cadence.moe/MRRPDggXQMYkrUjTpxQbmcxB'), ('https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml', 'mxc://cadence.moe/HnQIYQmmlIKwOQsbFsIGpzPP'), ('https://cdn.discordapp.com/attachments/112760669178241024/1296237494987133070/100km.gif', 'mxc://cadence.moe/qDAotmebTfEIfsAIVCEZptLh'), -('https://cdn.discordapp.com/attachments/123/456/my_enemies.txt', 'mxc://cadence.moe/y89EOTRp2lbeOkgdsEleGOge'); +('https://cdn.discordapp.com/attachments/123/456/my_enemies.txt', 'mxc://cadence.moe/y89EOTRp2lbeOkgdsEleGOge'), +('https://cdn.discordapp.com/emojis/1254940125948022915.webp', 'mxc://cadence.moe/bvVJFgOIyNcAknKCbmaHDktG'); INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES ('230201364309868544', 'hippo', 0, 'mxc://cadence.moe/qWmbXeRspZRLPcjseyLmeyXC'),