diff --git a/d2m/converters/message-to-event.js b/d2m/converters/message-to-event.js index 6fdf32e..f8f9b57 100644 --- a/d2m/converters/message-to-event.js +++ b/d2m/converters/message-to-event.js @@ -247,19 +247,8 @@ async function messageToEvent(message, guild, options = {}, di) { : 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: View (${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) { + if (attachment.size > reg.ooye.max_file_size) { return { $type: "m.room.message", "m.mentions": mentions, diff --git a/d2m/converters/message-to-event.test.js b/d2m/converters/message-to-event.test.js index 0f9260b..117cdac 100644 --- a/d2m/converters/message-to-event.test.js +++ b/d2m/converters/message-to-event.test.js @@ -104,18 +104,6 @@ test("message2event: attachment with no content", async t => { }]) }) -test("message2event: spoiler attachment", async t => { - const events = await messageToEvent(data.message.spoiler_attachment, data.guild.general, {}) - t.deepEqual(events, [{ - $type: "m.room.message", - "m.mentions": {}, - msgtype: "m.text", - body: "📄 Uploaded SPOILER file: https://cdn.discordapp.com/attachments/1100319550446252084/1147465564307079258/SPOILER_69-GNDP-CADENCE.nfs.gci (74 KB)", - format: "org.matrix.custom.html", - formatted_body: "
📄 Uploaded SPOILER file: View (74 KB)
" - }]) -}) - test("message2event: stickers", async t => { const events = await messageToEvent(data.message.sticker, data.guild.general, {}) t.deepEqual(events, [{ diff --git a/m2d/actions/send-event.js b/m2d/actions/send-event.js index e870675..18a1e0f 100644 --- a/m2d/actions/send-event.js +++ b/m2d/actions/send-event.js @@ -1,7 +1,6 @@ // @ts-check const assert = require("assert").strict -const Ty = require("../../types") const DiscordTypes = require("discord-api-types/v10") const passthrough = require("../../passthrough") const {sync, discord, db} = passthrough @@ -13,30 +12,9 @@ const eventToMessage = sync.require("../converters/event-to-message") /** @type {import("../../matrix/api")}) */ const api = sync.require("../../matrix/api") -/** - * @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {pendingFiles?: {name: string, url: string}[]}} message - * @returns {Promise} - */ -async function resolvePendingFiles(message) { - if (!message.pendingFiles) return message - const files = await Promise.all(message.pendingFiles.map(async p => { - const file = await fetch(p.url).then(res => res.arrayBuffer()).then(x => Buffer.from(x)) - return { - name: p.name, - file - } - })) - const newMessage = { - ...message, - files - } - delete newMessage.pendingFiles - return newMessage -} - -/** @param {Ty.Event.M_Outer_M_Room_Message | Ty.Event.M_Outer_M_Room_Message_File | Ty.Event.M_Outer_M_Sticker} event */ +/** @param {import("../../types").Event.Outer} event */ async function sendEvent(event) { - // TODO: we just assume the bridge has already been created, is that really ok? + // TODO: we just assume the bridge has already been created const row = db.prepare("SELECT channel_id, thread_parent FROM channel_room WHERE room_id = ?").get(event.room_id) let channelID = row.channel_id let threadID = undefined @@ -51,15 +29,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}) - - messagesToEdit = await Promise.all(messagesToEdit.map(async e => { - e.message = await resolvePendingFiles(e.message) - return e - })) - messagesToSend = await Promise.all(messagesToSend.map(message => { - return resolvePendingFiles(message) - })) + const {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api}) let eventPart = 0 // 0 is primary, 1 is supporting @@ -78,7 +48,7 @@ async function sendEvent(event) { for (const message of messagesToSend) { const messageResponse = await channelWebhook.sendMessageWithWebhook(channelID, message, threadID) db.prepare("REPLACE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(messageResponse.id, channelID) - db.prepare("INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, source) VALUES (?, ?, ?, ?, ?, 0)").run(event.event_id, event.type, event.content["msgtype"] || null, messageResponse.id, eventPart) // source 0 = matrix + db.prepare("INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, source) VALUES (?, ?, ?, ?, ?, 0)").run(event.event_id, event.type, event.content.msgtype || null, messageResponse.id, eventPart) // source 0 = matrix eventPart = 1 messageResponses.push(messageResponse) diff --git a/m2d/converters/event-to-message.js b/m2d/converters/event-to-message.js index a8a5b65..deb7b9f 100644 --- a/m2d/converters/event-to-message.js +++ b/m2d/converters/event-to-message.js @@ -4,7 +4,6 @@ const Ty = require("../../types") const DiscordTypes = require("discord-api-types/v10") const chunk = require("chunk-text") const TurndownService = require("turndown") -const assert = require("assert").strict const passthrough = require("../../passthrough") const { sync, db, discord } = passthrough @@ -125,7 +124,7 @@ async function getMemberFromCacheOrHomeserver(roomID, mxid, api) { } /** - * @param {Ty.Event.M_Outer_M_Room_Message | Ty.Event.M_Outer_M_Room_Message_File | Ty.Event.M_Outer_M_Sticker} event + * @param {Ty.Event.Outer} event * @param {import("discord-api-types/v10").APIGuild} guild * @param {{api: import("../../matrix/api")}} di simple-as-nails dependency injection for the matrix API */ @@ -144,15 +143,12 @@ async function eventToMessage(event, guild, di) { // Try to extract an accurate display name and avatar URL from the member event const member = await getMemberFromCacheOrHomeserver(event.room_id, event.sender, di?.api) if (member.displayname) displayName = member.displayname - if (member.avatar_url) avatarURL = utils.getPublicUrlForMxc(member.avatar_url) || undefined + if (member.avatar_url) avatarURL = utils.getPublicUrlForMxc(member.avatar_url) let content = event.content.body // ultimate fallback - const attachments = [] - /** @type {{name: string, url: string}[]} */ - const pendingFiles = [] // Convert content depending on what the message is - if (event.type === "m.room.message" && (event.content.msgtype === "m.text" || event.content.msgtype === "m.emote")) { + if (event.content.msgtype === "m.text" || event.content.msgtype === "m.emote") { // Handling edits. If the edit was an edit of a reply, edits do not include the reply reference, so we need to fetch up to 2 more events. // this event ---is an edit of--> original event ---is a reply to--> past event await (async () => { @@ -265,7 +261,7 @@ async function eventToMessage(event, guild, di) { // @ts-ignore bad type from turndown content = turndownService.turndown(input) - // It's designed for commonmark, we need to replace the space-space-newline with just newline + // It's optimised for commonmark, we need to replace the space-space-newline with just newline content = content.replace(/ \n/g, "\n") } else { // Looks like we're using the plaintext body! @@ -278,23 +274,6 @@ async function eventToMessage(event, guild, di) { // Markdown needs to be escaped content = content.replace(/([*_~`#])/g, `\\$1`) } - } else if (event.type === "m.room.message" && (event.content.msgtype === "m.file" || event.content.msgtype === "m.video" || event.content.msgtype === "m.audio" || event.content.msgtype === "m.image")) { - content = "" - const filename = event.content.body - const url = utils.getPublicUrlForMxc(event.content.url) - assert(url) - attachments.push({id: "0", filename}) - pendingFiles.push({name: filename, url}) - } else if (event.type === "m.sticker") { - content = "" - let filename = event.content.body - if (event.type === "m.sticker" && event.content.info.mimetype.includes("/")) { - filename += "." + event.content.info.mimetype.split("/")[1] - } - const url = utils.getPublicUrlForMxc(event.content.url) - assert(url) - attachments.push({id: "0", filename}) - pendingFiles.push({name: filename, url}) } content = replyLine + content @@ -307,19 +286,6 @@ async function eventToMessage(event, guild, di) { avatar_url: avatarURL }))) - if (attachments.length) { - // If content is empty (should be the case when uploading a file) then chunk-text will create 0 messages. - // There needs to be a message to add attachments to. - if (!messages.length) messages.push({ - content, - username: displayName, - avatar_url: avatarURL - }) - messages[0].attachments = attachments - // @ts-ignore these will be converted to real files when the message is about to be sent - messages[0].pendingFiles = pendingFiles - } - const messagesToEdit = [] const messagesToSend = [] for (let i = 0; i < messages.length; i++) { diff --git a/m2d/converters/event-to-message.test.js b/m2d/converters/event-to-message.test.js index 5a83f0c..411d97c 100644 --- a/m2d/converters/event-to-message.test.js +++ b/m2d/converters/event-to-message.test.js @@ -1110,107 +1110,3 @@ test("event2message: skips caching the member if the member does not exist, some t.deepEqual(db.prepare("SELECT avatar_url, displayname, mxid FROM member_cache WHERE room_id = '!not_real:cadence.moe'").all(), []) t.equal(called, 1, "getStateEvent should be called once") }) - -test("event2message: text attachments work", async t => { - t.deepEqual( - await eventToMessage({ - type: "m.room.message", - content: { - body: "chiki-powerups.txt", - info: { - size: 971, - mimetype: "text/plain" - }, - msgtype: "m.file", - url: "mxc://cadence.moe/zyThGlYQxvlvBVbVgKDDbiHH" - }, - sender: "@cadence:cadence.moe", - event_id: "$c2WVyP6KcfAqh5imOa8e0xzt2C8JTR-cWbEd3GargEQ", - room_id: "!PnyBKvUBOhjuCucEfk:cadence.moe" - }), - { - messagesToDelete: [], - messagesToEdit: [], - messagesToSend: [{ - username: "cadence [they]", - content: "", - avatar_url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/azCAhThKTojXSZJRoWwZmhvU", - attachments: [{id: "0", filename: "chiki-powerups.txt"}], - pendingFiles: [{name: "chiki-powerups.txt", url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/zyThGlYQxvlvBVbVgKDDbiHH"}] - }] - } - ) -}) - -test("event2message: image attachments work", async t => { - t.deepEqual( - await eventToMessage({ - type: "m.room.message", - sender: "@cadence:cadence.moe", - content: { - body: "cool cat.png", - info: { - size: 43170, - mimetype: "image/png", - w: 480, - h: 480, - "xyz.amorgan.blurhash": "URTHsVaTpdj2eKZgkkkXp{pHl7feo@lSl9Z$" - }, - msgtype: "m.image", - url: "mxc://cadence.moe/IvxVJFLEuksCNnbojdSIeEvn" - }, - event_id: "$CXQy3Wmg1A-gL_xAesC1HQcQTEXwICLdSwwUx55FBTI", - room_id: "!PnyBKvUBOhjuCucEfk:cadence.moe" - }), - { - messagesToDelete: [], - messagesToEdit: [], - messagesToSend: [{ - username: "cadence [they]", - content: "", - avatar_url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/azCAhThKTojXSZJRoWwZmhvU", - attachments: [{id: "0", filename: "cool cat.png"}], - pendingFiles: [{name: "cool cat.png", url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/IvxVJFLEuksCNnbojdSIeEvn"}] - }] - } - ) -}) - -test("event2message: stickers work", async t => { - t.deepEqual( - await eventToMessage({ - type: "m.sticker", - sender: "@cadence:cadence.moe", - content: { - body: "get_real2", - url: "mxc://cadence.moe/NyMXQFAAdniImbHzsygScbmN", - info: { - w: 320, - h: 298, - mimetype: "image/gif", - size: 331394, - thumbnail_info: { - w: 320, - h: 298, - mimetype: "image/gif", - size: 331394 - }, - thumbnail_url: "mxc://cadence.moe/NyMXQFAAdniImbHzsygScbmN" - } - }, - event_id: "$PdI-KjdQ8Z_Tb4x9_7wKRPZCsrrXym4BXtbAPekypuM", - room_id: "!PnyBKvUBOhjuCucEfk:cadence.moe" - }), - { - messagesToDelete: [], - messagesToEdit: [], - messagesToSend: [{ - username: "cadence [they]", - content: "", - avatar_url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/azCAhThKTojXSZJRoWwZmhvU", - attachments: [{id: "0", filename: "get_real2.gif"}], - pendingFiles: [{name: "get_real2.gif", url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/NyMXQFAAdniImbHzsygScbmN"}] - }] - } - ) -}) diff --git a/m2d/event-dispatcher.js b/m2d/event-dispatcher.js index 026b067..6adacf7 100644 --- a/m2d/event-dispatcher.js +++ b/m2d/event-dispatcher.js @@ -54,16 +54,7 @@ function guard(type, fn) { sync.addTemporaryListener(as, "type:m.room.message", guard("m.room.message", /** - * @param {Ty.Event.M_Outer_M_Room_Message | Ty.Event.M_Outer_M_Room_Message_File} event it is a m.room.message because that's what this listener is filtering for - */ -async event => { - if (utils.eventSenderIsFromDiscord(event.sender)) return - const messageResponses = await sendEvent.sendEvent(event) -})) - -sync.addTemporaryListener(as, "type:m.sticker", guard("m.sticker", -/** - * @param {Ty.Event.M_Outer_M_Sticker} event it is a m.sticker because that's what this listener is filtering for + * @param {Ty.Event.Outer} event it is a m.room.message because that's what this listener is filtering for */ async event => { if (utils.eventSenderIsFromDiscord(event.sender)) return diff --git a/test/data.js b/test/data.js index 98c943a..32ee3b0 100644 --- a/test/data.js +++ b/test/data.js @@ -531,44 +531,6 @@ module.exports = { flags: 0, components: [] }, - spoiler_attachment: { - type: 0, - tts: false, - timestamp: '2023-09-02T09:38:29.480000+00:00', - referenced_message: null, - pinned: false, - nonce: '1147465562901708800', - mentions: [], - mention_roles: [], - mention_everyone: false, - id: '1147465564600676383', - flags: 0, - embeds: [], - edited_timestamp: null, - content: '', - components: [], - channel_id: '1100319550446252084', - author: { - username: 'cadence.worm', - public_flags: 0, - id: '772659086046658620', - global_name: 'cadence', - discriminator: '0', - avatar_decoration_data: null, - avatar: '4b5c4b28051144e4c111f0113a0f1cf1' - }, - attachments: [ - { - url: 'https://cdn.discordapp.com/attachments/1100319550446252084/1147465564307079258/SPOILER_69-GNDP-CADENCE.nfs.gci', - size: 73792, - proxy_url: 'https://media.discordapp.net/attachments/1100319550446252084/1147465564307079258/SPOILER_69-GNDP-CADENCE.nfs.gci', - id: '1147465564307079258', - flags: 8, - filename: 'SPOILER_69-GNDP-CADENCE.nfs.gci' - } - ], - guild_id: '1100319549670301727' - }, skull_webp_attachment_with_content: { type: 0, tts: false, diff --git a/types.d.ts b/types.d.ts index b74172b..dcde3ad 100644 --- a/types.d.ts +++ b/types.d.ts @@ -80,39 +80,6 @@ export namespace Event { } } - export type M_Outer_M_Room_Message = Outer & {type: "m.room.message"} - - export type M_Room_Message_File = { - msgtype: "m.file" | "m.image" | "m.video" | "m.audio" - body: string - url: string - info?: any - "m.relates_to"?: { - "m.in_reply_to": { - event_id: string - } - rel_type?: "m.replace" - event_id?: string - } - } - - export type M_Outer_M_Room_Message_File = Outer & {type: "m.room.message"} - - export type M_Sticker = { - body: string - url: string - info: { - mimetype: string - w?: number - h?: number - size?: number - thumbnail_info?: any - thumbnail_url?: string - } - } - - export type M_Outer_M_Sticker = Outer & {type: "m.sticker"} - export type M_Room_Member = { membership: string displayname?: string