diff --git a/d2m/converters/message-to-event.js b/d2m/converters/message-to-event.js index 5994ff3..78985fa 100644 --- a/d2m/converters/message-to-event.js +++ b/d2m/converters/message-to-event.js @@ -86,103 +86,6 @@ const embedTitleParser = markdown.markdownEngine.parserFor({ link: undefined }) -/** - * @param {{room?: boolean, user_ids?: string[]}} mentions - * @param {DiscordTypes.APIAttachment} attachment - */ -async function attachmentToEvent(mentions, attachment) { - const emoji = - attachment.content_type?.startsWith("image/jp") ? "📸" - : attachment.content_type?.startsWith("image/") ? "🖼️" - : attachment.content_type?.startsWith("video/") ? "🎞️" - : attachment.content_type?.startsWith("text/") ? "📝" - : attachment.content_type?.startsWith("audio/") ? "🎶" - : "📄" - // no native media spoilers in Element, so we'll post a link instead, forcing it to not preview using a blockquote - if (attachment.filename.startsWith("SPOILER_")) { - return { - $type: "m.room.message", - "m.mentions": mentions, - msgtype: "m.text", - body: `${emoji} Uploaded SPOILER file: ${attachment.url} (${pb(attachment.size)})`, - format: "org.matrix.custom.html", - formatted_body: `
${emoji} Uploaded SPOILER file: ${attachment.url} (${pb(attachment.size)})` - } - } - // for large files, always link them instead of uploading so I don't use up all the space in the content repo - else if (attachment.size > reg.ooye.max_file_size) { - return { - $type: "m.room.message", - "m.mentions": mentions, - msgtype: "m.text", - body: `${emoji} Uploaded file: ${attachment.url} (${pb(attachment.size)})`, - format: "org.matrix.custom.html", - formatted_body: `${emoji} Uploaded file: ${attachment.filename} (${pb(attachment.size)})` - } - } else if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) { - return { - $type: "m.room.message", - "m.mentions": mentions, - msgtype: "m.image", - url: await file.uploadDiscordFileToMxc(attachment.url), - external_url: attachment.url, - body: attachment.filename, - filename: attachment.filename, - info: { - mimetype: attachment.content_type, - w: attachment.width, - h: attachment.height, - size: attachment.size - } - } - } else if (attachment.content_type?.startsWith("video/") && attachment.width && attachment.height) { - return { - $type: "m.room.message", - "m.mentions": mentions, - msgtype: "m.video", - url: await file.uploadDiscordFileToMxc(attachment.url), - external_url: attachment.url, - body: attachment.description || attachment.filename, - filename: attachment.filename, - info: { - mimetype: attachment.content_type, - w: attachment.width, - h: attachment.height, - size: attachment.size - } - } - } else if (attachment.content_type?.startsWith("audio/")) { - return { - $type: "m.room.message", - "m.mentions": mentions, - msgtype: "m.audio", - url: await file.uploadDiscordFileToMxc(attachment.url), - external_url: attachment.url, - body: attachment.description || attachment.filename, - filename: attachment.filename, - info: { - mimetype: attachment.content_type, - size: attachment.size, - duration: attachment.duration_secs ? attachment.duration_secs * 1000 : undefined - } - } - } else { - return { - $type: "m.room.message", - "m.mentions": mentions, - msgtype: "m.file", - url: await file.uploadDiscordFileToMxc(attachment.url), - external_url: attachment.url, - body: attachment.filename, - filename: attachment.filename, - info: { - mimetype: attachment.content_type, - size: attachment.size - } - } - } -} - /** * @param {import("discord-api-types/v10").APIMessage} message * @param {import("discord-api-types/v10").APIGuild} guild @@ -413,7 +316,98 @@ async function messageToEvent(message, guild, options = {}, di) { } // Then attachments - const attachmentEvents = await Promise.all(message.attachments.map(attachmentToEvent.bind(null, mentions))) + const attachmentEvents = await Promise.all(message.attachments.map(async attachment => { + const emoji = + attachment.content_type?.startsWith("image/jp") ? "📸" + : attachment.content_type?.startsWith("image/") ? "🖼️" + : attachment.content_type?.startsWith("video/") ? "🎞️" + : attachment.content_type?.startsWith("text/") ? "📝" + : attachment.content_type?.startsWith("audio/") ? "🎶" + : "📄" + // no native media spoilers in Element, so we'll post a link instead, forcing it to not preview using a blockquote + if (attachment.filename.startsWith("SPOILER_")) { + return { + $type: "m.room.message", + "m.mentions": mentions, + msgtype: "m.text", + body: `${emoji} Uploaded SPOILER file: ${attachment.url} (${pb(attachment.size)})`, + format: "org.matrix.custom.html", + formatted_body: `
${emoji} Uploaded SPOILER file: ${attachment.url} (${pb(attachment.size)})` + } + } + // for large files, always link them instead of uploading so I don't use up all the space in the content repo + else if (attachment.size > reg.ooye.max_file_size) { + return { + $type: "m.room.message", + "m.mentions": mentions, + msgtype: "m.text", + body: `${emoji} Uploaded file: ${attachment.url} (${pb(attachment.size)})`, + format: "org.matrix.custom.html", + formatted_body: `${emoji} Uploaded file: ${attachment.filename} (${pb(attachment.size)})` + } + } else if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) { + return { + $type: "m.room.message", + "m.mentions": mentions, + msgtype: "m.image", + url: await file.uploadDiscordFileToMxc(attachment.url), + external_url: attachment.url, + body: attachment.filename, + filename: attachment.filename, + info: { + mimetype: attachment.content_type, + w: attachment.width, + h: attachment.height, + size: attachment.size + } + } + } else if (attachment.content_type?.startsWith("video/") && attachment.width && attachment.height) { + return { + $type: "m.room.message", + "m.mentions": mentions, + msgtype: "m.video", + url: await file.uploadDiscordFileToMxc(attachment.url), + external_url: attachment.url, + body: attachment.description || attachment.filename, + filename: attachment.filename, + info: { + mimetype: attachment.content_type, + w: attachment.width, + h: attachment.height, + size: attachment.size + } + } + } else if (attachment.content_type?.startsWith("audio/")) { + return { + $type: "m.room.message", + "m.mentions": mentions, + msgtype: "m.audio", + url: await file.uploadDiscordFileToMxc(attachment.url), + external_url: attachment.url, + body: attachment.description || attachment.filename, + filename: attachment.filename, + info: { + mimetype: attachment.content_type, + size: attachment.size, + duration: attachment.duration_secs ? attachment.duration_secs * 1000 : undefined + } + } + } else { + return { + $type: "m.room.message", + "m.mentions": mentions, + msgtype: "m.file", + url: await file.uploadDiscordFileToMxc(attachment.url), + external_url: attachment.url, + body: attachment.filename, + filename: attachment.filename, + info: { + mimetype: attachment.content_type, + size: attachment.size + } + } + } + })) events.push(...attachmentEvents) // Then embeds diff --git a/m2d/actions/send-event.js b/m2d/actions/send-event.js index f26abb0..9b3fbec 100644 --- a/m2d/actions/send-event.js +++ b/m2d/actions/send-event.js @@ -73,7 +73,7 @@ async function sendEvent(event) { // no need to sync the matrix member to the other side. but if I did need to, this is where I'd do it - let {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api, snow: discord.snow}) + let {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api}) messagesToEdit = await Promise.all(messagesToEdit.map(async e => { e.message = await resolvePendingFiles(e.message) diff --git a/m2d/converters/event-to-message.js b/m2d/converters/event-to-message.js index ef913bb..7082fbb 100644 --- a/m2d/converters/event-to-message.js +++ b/m2d/converters/event-to-message.js @@ -122,7 +122,7 @@ turndownService.addRule("listItem", { if (parent.nodeName === "OL") { var start = parent.getAttribute("start") var index = Array.prototype.indexOf.call(parent.children, node) - prefix = (start ? Number(start) + index : index + 1) + ". " + prefix = (start ? Number(start) + index : index + 1) + ". " } return prefix + content + (node.nextSibling && !/\n$/.test(content) ? "\n" : "") } @@ -259,7 +259,7 @@ async function uploadEndOfMessageSpriteSheet(content, attachments, pendingFiles) /** * @param {Ty.Event.Outer_M_Room_Message | Ty.Event.Outer_M_Room_Message_File | Ty.Event.Outer_M_Sticker | Ty.Event.Outer_M_Room_Message_Encrypted_File} event * @param {import("discord-api-types/v10").APIGuild} guild - * @param {{api: import("../../matrix/api"), snow: import("snowtransfer").SnowTransfer}} di simple-as-nails dependency injection for the matrix API + * @param {{api: import("../../matrix/api")}} di simple-as-nails dependency injection for the matrix API */ async function eventToMessage(event, guild, di) { /** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[]})[]} */ @@ -289,8 +289,6 @@ async function eventToMessage(event, guild, di) { const attachments = [] /** @type {({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer})[]} */ const pendingFiles = [] - /** @type {DiscordTypes.APIUser[]} */ - const ensureJoined = [] // Convert content depending on what the message is if (event.type === "m.room.message" && (event.content.msgtype === "m.text" || event.content.msgtype === "m.emote")) { @@ -504,17 +502,6 @@ async function eventToMessage(event, guild, di) { content = displayNameRunoff + replyLine + content - // Handling written @mentions: we need to look for candidate Discord members to join to the room - let writtenMentionMatch = content.match(/(?:^|[^"<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // d flag requires Node 16+ - if (writtenMentionMatch) { - const results = await di.snow.guild.searchGuildMembers(guild.id, {query: writtenMentionMatch[1]}) - if (results[0]) { - assert(results[0].user) - content = content.slice(0, writtenMentionMatch.index) + `<@${results[0].user.id}>` + content.slice(writtenMentionMatch.index + writtenMentionMatch[0].length) - ensureJoined.push(results[0].user) - } - } - // Split into 2000 character chunks const chunks = chunk(content, 2000) messages = messages.concat(chunks.map(content => ({ @@ -556,8 +543,7 @@ async function eventToMessage(event, guild, di) { return { messagesToEdit, messagesToSend, - messagesToDelete: messageIDsToEdit, - ensureJoined + messagesToDelete: messageIDsToEdit } } diff --git a/m2d/converters/event-to-message.test.js b/m2d/converters/event-to-message.test.js index 8bd4223..f564906 100644 --- a/m2d/converters/event-to-message.test.js +++ b/m2d/converters/event-to-message.test.js @@ -63,7 +63,6 @@ test("event2message: body is used when there is no formatted_body", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -90,15 +89,8 @@ test("event2message: any markdown in body is escaped, except strikethrough", asy unsigned: { age: 405299 } - }, {}, { - snow: { - guild: { - searchGuildMembers: () => [] - } - } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -130,7 +122,6 @@ test("event2message: links in formatted body are not broken", async t => { room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe" }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -160,7 +151,6 @@ test("event2message: links in plaintext body are not broken", async t => { room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe" }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -191,7 +181,6 @@ test("event2message: basic html is converted to markdown", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -222,7 +211,6 @@ test("event2message: spoilers work", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -253,7 +241,6 @@ test("event2message: markdown syntax is escaped", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -284,7 +271,6 @@ test("event2message: html lines are bridged correctly", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -315,7 +301,6 @@ test("event2message: html lines are bridged correctly", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -347,7 +332,6 @@ test("event2message: whitespace is collapsed", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -380,7 +364,6 @@ test("event2message: lists are bridged correctly", async t => { "room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe" }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -409,7 +392,6 @@ test("event2message: long messages are split", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -444,7 +426,6 @@ test("event2message: code blocks work", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -476,7 +457,6 @@ test("event2message: code block contents are formatted correctly and not escaped "room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe" }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -507,7 +487,6 @@ test("event2message: quotes have an appropriate amount of whitespace", async t = } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -549,7 +528,6 @@ test("event2message: lists have appropriate line breaks", async t => { } }), { - ensureJoined: [], messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ @@ -561,48 +539,6 @@ test("event2message: lists have appropriate line breaks", async t => { ) }) -test("event2message: ordered list start attribute works", async t => { - t.deepEqual( - await eventToMessage({ - content: { - body: 'i am not certain what you mean by "already exists with as discord". my goals are\n' + - '1. bridgeing specific channels with existing matrix rooms\n' + - ' 2. optionally maybe entire "servers"\n' + - '3. offering the bridge as a public service ', - format: 'org.matrix.custom.html', - formatted_body: '
i am not certain what you mean by "already exists with as discord". my goals are
\n' + - '