Support forwarded messages

This commit is contained in:
Cadence Ember 2024-10-31 17:34:25 +13:00
parent ac165845d7
commit 49948ae2c1
3 changed files with 84 additions and 11 deletions

View file

@ -428,6 +428,12 @@ async function messageToEvent(message, guild, options = {}, di) {
return {body, html} return {body, html}
} }
/**
* After converting Discord content to Matrix plaintext and HTML content, post-process the bodies and push the resulting text event
* @param {string} body matrix event plaintext body
* @param {string} html matrix event HTML body
* @param {string} msgtype matrix event msgtype (maybe m.text or m.notice)
*/
async function addTextEvent(body, html, msgtype) { async function addTextEvent(body, html, msgtype) {
// Star * prefix for fallback edits // Star * prefix for fallback edits
if (options.includeEditFallbackStar) { if (options.includeEditFallbackStar) {
@ -436,7 +442,7 @@ async function messageToEvent(message, guild, options = {}, di) {
} }
const flags = message.flags || 0 const flags = message.flags || 0
if (flags & 2) { if (flags & DiscordTypes.MessageFlags.IsCrosspost) {
body = `[🔀 ${message.author.username}]\n` + body body = `[🔀 ${message.author.username}]\n` + body
html = `🔀 <strong>${message.author.username}</strong><br>` + html html = `🔀 <strong>${message.author.username}</strong><br>` + html
} }
@ -508,7 +514,57 @@ async function messageToEvent(message, guild, options = {}, di) {
message.content = "changed the channel name to **" + message.content + "**" message.content = "changed the channel name to **" + message.content + "**"
} }
// Forwarded content appears first
if (message.message_reference?.type === DiscordTypes.MessageReferenceType.Forward && message.message_snapshots?.length) {
// Forwarded notice
const eventID = select("event_message", "event_id", {message_id: message.message_reference.message_id}).pluck().get()
const room = select("channel_room", ["room_id", "name", "nick"], {channel_id: message.message_reference.channel_id}).get()
const forwardedNotice = new mxUtils.MatrixStringBuilder()
if (eventID && room) {
const via = await getViaServersMemo(room.room_id)
forwardedNotice.addLine(
`[🔀 Forwarded from #${room.nick || room.name}]`,
tag`🔀 <em>Forwarded from <a href="https://matrix.to/#/${room.room_id}/${eventID}?${via}">${room.nick || room.name}</a></em>`
)
} else if (room) {
const via = await getViaServersMemo(room.room_id)
forwardedNotice.addLine(
`[🔀 Forwarded from #${room.nick || room.name}]`,
tag`🔀 <em>Forwarded from <a href="https://matrix.to/#/${room.room_id}?${via}">${room.nick || room.name}</a></em>`
)
} else {
forwardedNotice.addLine(
`[🔀 Forwarded message]`,
tag`🔀 <em>Forwarded message</em>`
)
}
// Forwarded content
// @ts-ignore
const forwardedEvents = await messageToEvent(message.message_snapshots[0].message, guild, {includeReplyFallback: false, includeEditFallbackStar: false}, di)
// Indent
for (const event of forwardedEvents) {
if (["m.text", "m.notice"].includes(event.msgtype)) {
event.msgtype = "m.notice"
event.body = event.body.split("\n").map(l => "» " + l).join("\n")
event.formatted_body = `<blockquote>${event.formatted_body}</blockquote>`
}
}
// Try to merge the forwarded content with the forwarded notice
let {body, formatted_body} = forwardedNotice.get()
if (forwardedEvents.length >= 1 && ["m.text", "m.notice"].includes(forwardedEvents[0].msgtype)) { // Try to merge the forwarded content and the forwarded notice
forwardedNotice.add("\n", "<br>")
forwardedEvents[0].body = body + forwardedEvents[0].body
forwardedEvents[0].formatted_body = formatted_body + forwardedEvents[0].formatted_body
} else {
await addTextEvent(body, formatted_body, "m.notice")
}
events.push(...forwardedEvents)
}
// Then text content
if (message.content) { if (message.content) {
// Mentions scenario 3: scan the message content for written @mentions of matrix users. Allows for up to one space between @ and mention. // Mentions scenario 3: scan the message content for written @mentions of matrix users. Allows for up to one space between @ and mention.
const matches = [...message.content.matchAll(/@ ?([a-z0-9._]+)\b/gi)] const matches = [...message.content.matchAll(/@ ?([a-z0-9._]+)\b/gi)]
@ -527,7 +583,6 @@ async function messageToEvent(message, guild, options = {}, di) {
} }
} }
// Text content appears first
const {body, html} = await transformContent(message.content) const {body, html} = await transformContent(message.content)
await addTextEvent(body, html, msgtype) await addTextEvent(body, html, msgtype)
} }

View file

@ -1017,12 +1017,29 @@ test("message2event: @everyone within a link", async t => {
test("message2event: forwarded image", async t => { test("message2event: forwarded image", async t => {
const events = await messageToEvent(data.message.forwarded_image) const events = await messageToEvent(data.message.forwarded_image)
t.deepEqual(events, [{ t.deepEqual(events, [
$type: "m.room.message", {
msgtype: "m.text", $type: "m.room.message",
body: "https://github.com/@everyone", body: "[🔀 Forwarded message]",
format: "org.matrix.custom.html", format: "org.matrix.custom.html",
formatted_body: `<a href="https://github.com/@everyone">https://github.com/@everyone</a>`, formatted_body: "🔀 <em>Forwarded message</em>",
"m.mentions": {} "m.mentions": {},
}]) msgtype: "m.notice",
},
{
$type: "m.room.message",
body: "100km.gif",
external_url: "https://bridge.example.org/download/discordcdn/112760669178241024/1296237494987133070/100km.gif",
filename: "100km.gif",
info: {
h: 300,
mimetype: "image/gif",
size: 2965649,
w: 300,
},
"m.mentions": {},
msgtype: "m.image",
url: "mxc://cadence.moe/qDAotmebTfEIfsAIVCEZptLh",
},
])
}) })

View file

@ -123,7 +123,8 @@ INSERT INTO file (discord_url, mxc_url) VALUES
('https://cdn.discordapp.com/emojis/288858540888686602.png', 'mxc://cadence.moe/mwZaCtRGAQQyOItagDeCocEO'), ('https://cdn.discordapp.com/emojis/288858540888686602.png', 'mxc://cadence.moe/mwZaCtRGAQQyOItagDeCocEO'),
('https://cdn.discordapp.com/attachments/112760669178241024/1197621094786531358/Ins_1960637570.mp4', 'mxc://cadence.moe/kMqLycqMURhVpwleWkmASpnU'), ('https://cdn.discordapp.com/attachments/112760669178241024/1197621094786531358/Ins_1960637570.mp4', 'mxc://cadence.moe/kMqLycqMURhVpwleWkmASpnU'),
('https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg', 'mxc://cadence.moe/MRRPDggXQMYkrUjTpxQbmcxB'), ('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/122155380120748034/1174514575220158545/the.yml', 'mxc://cadence.moe/HnQIYQmmlIKwOQsbFsIGpzPP'),
('https://cdn.discordapp.com/attachments/112760669178241024/1296237494987133070/100km.gif', 'mxc://cadence.moe/qDAotmebTfEIfsAIVCEZptLh');
INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES
('230201364309868544', 'hippo', 0, 'mxc://cadence.moe/qWmbXeRspZRLPcjseyLmeyXC'), ('230201364309868544', 'hippo', 0, 'mxc://cadence.moe/qWmbXeRspZRLPcjseyLmeyXC'),