forked from cadence/out-of-your-element
Finally get the embed tests passing
This commit is contained in:
parent
d5013dd7ea
commit
a56942cf14
4 changed files with 184 additions and 55 deletions
|
@ -34,7 +34,68 @@ test("message2event embeds: nothing but a field", async t => {
|
|||
t.deepEqual(events, [{
|
||||
$type: "m.room.message",
|
||||
"m.mentions": {},
|
||||
msgtype: "m.text",
|
||||
body: "Amanda"
|
||||
msgtype: "m.notice",
|
||||
body: "**Amanda 🎵#2192 :online:"
|
||||
+ "\nwillow tree, branch 0**"
|
||||
+ "\n**❯ Uptime:**\n3m 55s\n**❯ Memory:**\n64.45MB",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: '<strong>Amanda 🎵#2192 <img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/LCEqjStXCxvRQccEkuslXEyZ\" title=\":online:\" alt=\":online:\">'
|
||||
+ '<br>willow tree, branch 0</strong>'
|
||||
+ '<br><strong>❯ Uptime:</strong><br>3m 55s'
|
||||
+ '<br><strong>❯ Memory:</strong><br>64.45MB'
|
||||
}])
|
||||
})
|
||||
|
||||
test("message2event embeds: reply with just an embed", async t => {
|
||||
const events = await messageToEvent(data.message_with_embeds.reply_with_only_embed, data.guild.general, {})
|
||||
t.deepEqual(events, [{
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.notice",
|
||||
"m.mentions": {},
|
||||
body: "[**⏺️ dynastic (@dynastic)**](https://twitter.com/i/user/719631291747078145)"
|
||||
+ "\n\n**https://twitter.com/i/status/1707484191963648161**"
|
||||
+ "\n\ndoes anyone know where to find that one video of the really mysterious yam-like object being held up to a bunch of random objects, like clocks, and they have unexplained impossible reactions to it?"
|
||||
+ "\n\n**Retweets**"
|
||||
+ "\n119"
|
||||
+ "\n\n**Likes**"
|
||||
+ "\n5581"
|
||||
+ "\n\n— Twitter",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: '<a href="https://twitter.com/i/user/719631291747078145"><strong>⏺️ dynastic (@dynastic)</strong></a>'
|
||||
+ '<br><br><strong><a href="https://twitter.com/i/status/1707484191963648161">https://twitter.com/i/status/1707484191963648161</a></strong>'
|
||||
+ '<br><br>does anyone know where to find that one video of the really mysterious yam-like object being held up to a bunch of random objects, like clocks, and they have unexplained impossible reactions to it?'
|
||||
+ '<br><br><strong>Retweets</strong><br>119<br><br><strong>Likes</strong><br>5581<br><br>— Twitter'
|
||||
}])
|
||||
})
|
||||
|
||||
test("message2event embeds: image embed and attachment", async t => {
|
||||
const events = await messageToEvent(data.message_with_embeds.image_embed_and_attachment, data.guild.general, {}, {
|
||||
api: {
|
||||
async getJoinedMembers(roomID) {
|
||||
return {joined: []}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.deepEqual(events, [{
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.text",
|
||||
body: "https://tootsuite.net/Warp-Gate2.gif\ntanget: @ monster spawner",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: '<a href="https://tootsuite.net/Warp-Gate2.gif">https://tootsuite.net/Warp-Gate2.gif</a><br>tanget: @ monster spawner',
|
||||
"m.mentions": {}
|
||||
}, {
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.image",
|
||||
url: "mxc://cadence.moe/zAXdQriaJuLZohDDmacwWWDR",
|
||||
body: "Screenshot_20231001_034036.jpg",
|
||||
external_url: "https://cdn.discordapp.com/attachments/176333891320283136/1157854643037163610/Screenshot_20231001_034036.jpg?ex=651a1faa&is=6518ce2a&hm=eb5ca80a3fa7add8765bf404aea2028a28a2341e4a62435986bcdcf058da82f3&",
|
||||
filename: "Screenshot_20231001_034036.jpg",
|
||||
info: {
|
||||
h: 1170,
|
||||
w: 1080,
|
||||
size: 51981,
|
||||
mimetype: "image/jpeg"
|
||||
},
|
||||
"m.mentions": {}
|
||||
}])
|
||||
})
|
||||
|
|
|
@ -136,16 +136,7 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
addMention(repliedToEventSenderMxid)
|
||||
}
|
||||
|
||||
let msgtype = "m.text"
|
||||
// Handle message type 4, channel name changed
|
||||
if (message.type === DiscordTypes.MessageType.ChannelNameChange) {
|
||||
msgtype = "m.emote"
|
||||
message.content = "changed the channel name to **" + message.content + "**"
|
||||
}
|
||||
|
||||
// Text content appears first
|
||||
if (message.content) {
|
||||
let content = message.content
|
||||
async function addTextEvent(content, msgtype, {scanMentions}) {
|
||||
content = content.replace(/https:\/\/(?:ptb\.|canary\.|www\.)?discord(?:app)?\.com\/channels\/([0-9]+)\/([0-9]+)\/([0-9]+)/, (whole, guildID, channelID, messageID) => {
|
||||
const eventID = select("event_message", "event_id", "WHERE message_id = ?").pluck().get(messageID)
|
||||
const roomID = select("channel_room", "room_id", "WHERE channel_id = ?").pluck().get(channelID)
|
||||
|
@ -186,44 +177,21 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
escapeHTML: false,
|
||||
}, null, null)
|
||||
|
||||
for (const embed of message.embeds || []) {
|
||||
// Start building up a replica ("rep") of the embed in Discord-markdown format, which we will convert into both plaintext and formatted body at once
|
||||
let repParagraphs = []
|
||||
if (embed.author?.name) repParagraphs.push(`**${embed.author.name}**`)
|
||||
if (embed.title && embed.url) repParagraphs.push(`[**${embed.title}**](${embed.url})`)
|
||||
else if (embed.title) repParagraphs.push(`**${embed.title}**`)
|
||||
else if (embed.url) repParagraphs.push(`**${embed.url}**`)
|
||||
if (embed.description) repParagraphs.push(embed.description)
|
||||
for (const field of embed.fields || []) {
|
||||
repParagraphs.push(`**${field.name}**\n${field.value}`)
|
||||
}
|
||||
if (embed.footer?.text) repParagraphs.push(embed.footer.text)
|
||||
const repContent = repParagraphs.join("\n\n")
|
||||
|
||||
html += "<blockquote>" + markdown.toHTML(repContent, {
|
||||
discordCallback: getDiscordParseCallbacks(message, true)
|
||||
}, null, null) + "</blockquote>"
|
||||
|
||||
body += "\n\n" + markdown.toHTML(repContent, {
|
||||
discordCallback: getDiscordParseCallbacks(message, false),
|
||||
discordOnly: true,
|
||||
escapeHTML: false
|
||||
}, null, null)
|
||||
}
|
||||
|
||||
// Mentions scenario 3: scan the message content for written @mentions of matrix users. Allows for up to one space between @ and mention.
|
||||
const matches = [...content.matchAll(/@ ?([a-z0-9._]+)\b/gi)]
|
||||
if (matches.length && matches.some(m => m[1].match(/[a-z]/i))) {
|
||||
const writtenMentionsText = matches.map(m => m[1].toLowerCase())
|
||||
const roomID = select("channel_room", "room_id", "WHERE channel_id = ?").pluck().get(message.channel_id)
|
||||
assert(roomID)
|
||||
const {joined} = await di.api.getJoinedMembers(roomID)
|
||||
for (const [mxid, member] of Object.entries(joined)) {
|
||||
if (!userRegex.some(rx => mxid.match(rx))) {
|
||||
const localpart = mxid.match(/@([^:]*)/)
|
||||
assert(localpart)
|
||||
const displayName = member.displayname || localpart[1]
|
||||
if (writtenMentionsText.includes(localpart[1].toLowerCase()) || writtenMentionsText.includes(displayName.toLowerCase())) addMention(mxid)
|
||||
if (scanMentions) {
|
||||
const matches = [...content.matchAll(/@ ?([a-z0-9._]+)\b/gi)]
|
||||
if (matches.length && matches.some(m => m[1].match(/[a-z]/i))) {
|
||||
const writtenMentionsText = matches.map(m => m[1].toLowerCase())
|
||||
const roomID = select("channel_room", "room_id", "WHERE channel_id = ?").pluck().get(message.channel_id)
|
||||
assert(roomID)
|
||||
const {joined} = await di.api.getJoinedMembers(roomID)
|
||||
for (const [mxid, member] of Object.entries(joined)) {
|
||||
if (!userRegex.some(rx => mxid.match(rx))) {
|
||||
const localpart = mxid.match(/@([^:]*)/)
|
||||
assert(localpart)
|
||||
const displayName = member.displayname || localpart[1]
|
||||
if (writtenMentionsText.includes(localpart[1].toLowerCase()) || writtenMentionsText.includes(displayName.toLowerCase())) addMention(mxid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,6 +254,19 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
events.push(newTextMessageEvent)
|
||||
}
|
||||
|
||||
|
||||
let msgtype = "m.text"
|
||||
// Handle message type 4, channel name changed
|
||||
if (message.type === DiscordTypes.MessageType.ChannelNameChange) {
|
||||
msgtype = "m.emote"
|
||||
message.content = "changed the channel name to **" + message.content + "**"
|
||||
}
|
||||
|
||||
// Text content appears first
|
||||
if (message.content) {
|
||||
await addTextEvent(message.content, msgtype, {scanMentions: true})
|
||||
}
|
||||
|
||||
// Then attachments
|
||||
const attachmentEvents = await Promise.all(message.attachments.map(async attachment => {
|
||||
const emoji =
|
||||
|
@ -381,6 +362,39 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
}))
|
||||
events.push(...attachmentEvents)
|
||||
|
||||
// Then embeds
|
||||
for (const embed of message.embeds || []) {
|
||||
if (embed.type === "image") {
|
||||
continue // Matrix already does a fine enough job of providing image embeds.
|
||||
}
|
||||
|
||||
// Start building up a replica ("rep") of the embed in Discord-markdown format, which we will convert into both plaintext and formatted body at once
|
||||
let repParagraphs = []
|
||||
const makeUrlTitle = (text, url) =>
|
||||
( text && url ? `[**${text}**](${url})`
|
||||
: text ? `**${text}**`
|
||||
: url ? `**${url}**`
|
||||
: "")
|
||||
|
||||
let authorNameText = embed.author?.name || ""
|
||||
if (authorNameText && embed.author?.icon_url) authorNameText = `⏺️ ${authorNameText}` // not using the real image
|
||||
let authorTitle = makeUrlTitle(authorNameText, embed.author?.url)
|
||||
if (authorTitle) repParagraphs.push(authorTitle)
|
||||
|
||||
let title = makeUrlTitle(embed.title, embed.url)
|
||||
if (title) repParagraphs.push(title)
|
||||
|
||||
if (embed.description) repParagraphs.push(embed.description)
|
||||
for (const field of embed.fields || []) {
|
||||
repParagraphs.push(`**${field.name}**\n${field.value}`)
|
||||
}
|
||||
if (embed.footer?.text) repParagraphs.push(`— ${embed.footer.text}`)
|
||||
const repContent = repParagraphs.join("\n\n")
|
||||
|
||||
// Send as m.notice to apply the usual automated/subtle appearance, showing this wasn't actually typed by the person
|
||||
await addTextEvent(repContent, "m.notice", {scanMentions: false})
|
||||
}
|
||||
|
||||
// Then stickers
|
||||
if (message.sticker_items) {
|
||||
const stickerEvents = await Promise.all(message.sticker_items.map(async stickerItem => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue