begin converting discord attachments and stickers
This commit is contained in:
		
							parent
							
								
									38d7db5071
								
							
						
					
					
						commit
						e1d7ced87d
					
				
					 6 changed files with 194 additions and 33 deletions
				
			
		| 
						 | 
					@ -19,16 +19,31 @@ const createRoom = sync.require("../actions/create-room")
 | 
				
			||||||
async function sendMessage(message) {
 | 
					async function sendMessage(message) {
 | 
				
			||||||
	assert.ok(message.member)
 | 
						assert.ok(message.member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const event = messageToEvent.messageToEvent(message)
 | 
					 | 
				
			||||||
	const roomID = await createRoom.ensureRoom(message.channel_id)
 | 
						const roomID = await createRoom.ensureRoom(message.channel_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let senderMxid = null
 | 
						let senderMxid = null
 | 
				
			||||||
	if (!message.webhook_id) {
 | 
						if (!message.webhook_id) {
 | 
				
			||||||
		senderMxid = await registerUser.ensureSimJoined(message.author, roomID)
 | 
							senderMxid = await registerUser.ensureSimJoined(message.author, roomID)
 | 
				
			||||||
		await registerUser.syncUser(message.author, message.member, message.guild_id, roomID)
 | 
							await registerUser.syncUser(message.author, message.member, message.guild_id, roomID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	const eventID = await api.sendEvent(roomID, "m.room.message", event, senderMxid)
 | 
					
 | 
				
			||||||
	db.prepare("INSERT INTO event_message (event_id, message_id, part) VALUES (?, ?, ?)").run(eventID, message.id, 0) // 0 is primary, 1 is supporting
 | 
						const events = await messageToEvent.messageToEvent(message)
 | 
				
			||||||
	return eventID
 | 
						const eventIDs = []
 | 
				
			||||||
 | 
						let eventPart = 0 // 0 is primary, 1 is supporting
 | 
				
			||||||
 | 
						for (const event of events) {
 | 
				
			||||||
 | 
							const eventType = event.$type
 | 
				
			||||||
 | 
							/** @type {Pick<typeof event, Exclude<keyof event, "$type">> & { $type?: string }} */
 | 
				
			||||||
 | 
							const eventWithoutType = {...event}
 | 
				
			||||||
 | 
							delete eventWithoutType.$type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const eventID = await api.sendEvent(roomID, eventType, event, senderMxid)
 | 
				
			||||||
 | 
							db.prepare("INSERT INTO event_message (event_id, message_id, part) VALUES (?, ?, ?)").run(eventID, message.id, eventPart)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							eventPart = 1 // TODO: use more intelligent algorithm to determine whether primary or supporting
 | 
				
			||||||
 | 
							eventIDs.push(eventID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return eventIDs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.sendMessage = sendMessage
 | 
					module.exports.sendMessage = sendMessage
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,27 +2,93 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const markdown = require("discord-markdown")
 | 
					const markdown = require("discord-markdown")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const passthrough = require("../../passthrough")
 | 
				
			||||||
 | 
					const { sync, db } = passthrough
 | 
				
			||||||
 | 
					/** @type {import("../../matrix/file")} */
 | 
				
			||||||
 | 
					const file = sync.require("../../matrix/file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIMessage} message
 | 
					 * @param {import("discord-api-types/v10").APIMessage} message
 | 
				
			||||||
 * @returns {import("../../types").Event.M_Room_Message}
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function messageToEvent(message) {
 | 
					async function messageToEvent(message) {
 | 
				
			||||||
 | 
						const events = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Text content appears first
 | 
				
			||||||
	const body = message.content
 | 
						const body = message.content
 | 
				
			||||||
	const html = markdown.toHTML(body, {
 | 
						const html = markdown.toHTML(body, {
 | 
				
			||||||
		/* discordCallback: {
 | 
							discordCallback: {
 | 
				
			||||||
			user: Function,
 | 
								user: node => {
 | 
				
			||||||
			channel: Function,
 | 
									const mxid = db.prepare("SELECT mxid FROM sim WHERE discord_id = ?").pluck().get(node.id)
 | 
				
			||||||
			role: Function,
 | 
									if (mxid) {
 | 
				
			||||||
			everyone: Function,
 | 
										return "https://matrix.to/#/" + mxid
 | 
				
			||||||
			here: Function
 | 
									} else {
 | 
				
			||||||
		} */
 | 
										return "@" + node.id
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								channel: node => {
 | 
				
			||||||
 | 
									const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(node.id)
 | 
				
			||||||
 | 
									if (roomID) {
 | 
				
			||||||
 | 
										return "https://matrix.to/#/" + roomID
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										return "#" + node.id
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								role: node =>
 | 
				
			||||||
 | 
									"@&" + node.id,
 | 
				
			||||||
 | 
								everyone: node =>
 | 
				
			||||||
 | 
									"@room",
 | 
				
			||||||
 | 
								here: node =>
 | 
				
			||||||
 | 
									"@here"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}, null, null)
 | 
						}, null, null)
 | 
				
			||||||
	return {
 | 
						const isPlaintext = body === html
 | 
				
			||||||
 | 
						if (isPlaintext) {
 | 
				
			||||||
 | 
							events.push({
 | 
				
			||||||
 | 
								$type: "m.room.message",
 | 
				
			||||||
 | 
								msgtype: "m.text",
 | 
				
			||||||
 | 
								body: body
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							events.push({
 | 
				
			||||||
 | 
								$type: "m.room.message",
 | 
				
			||||||
			msgtype: "m.text",
 | 
								msgtype: "m.text",
 | 
				
			||||||
			body: body,
 | 
								body: body,
 | 
				
			||||||
			format: "org.matrix.custom.html",
 | 
								format: "org.matrix.custom.html",
 | 
				
			||||||
			formatted_body: html
 | 
								formatted_body: html
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Then attachments
 | 
				
			||||||
 | 
						const attachmentEvents = await Promise.all(message.attachments.map(async attachment => {
 | 
				
			||||||
 | 
							// TODO: handle large files differently - link them instead of uploading
 | 
				
			||||||
 | 
							if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) {
 | 
				
			||||||
 | 
								return {
 | 
				
			||||||
 | 
									$type: "m.room.message",
 | 
				
			||||||
 | 
									msgtype: "m.image",
 | 
				
			||||||
 | 
									url: await file.uploadDiscordFileToMxc(attachment.url),
 | 
				
			||||||
 | 
									external_url: attachment.url,
 | 
				
			||||||
 | 
									body: attachment.filename,
 | 
				
			||||||
 | 
									// TODO: filename: attachment.filename and then use body as the caption
 | 
				
			||||||
 | 
									info: {
 | 
				
			||||||
 | 
										mimetype: attachment.content_type,
 | 
				
			||||||
 | 
										w: attachment.width,
 | 
				
			||||||
 | 
										h: attachment.height,
 | 
				
			||||||
 | 
										size: attachment.size
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return {
 | 
				
			||||||
 | 
									$type: "m.room.message",
 | 
				
			||||||
 | 
									msgtype: "m.text",
 | 
				
			||||||
 | 
									body: "Unsupported attachment:\n" + JSON.stringify(attachment, null, 2)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						events.push(...attachmentEvents)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Then stickers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return events
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.messageToEvent = messageToEvent
 | 
					module.exports.messageToEvent = messageToEvent
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								d2m/converters/message-to-event.test.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								d2m/converters/message-to-event.test.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					const {test} = require("supertape")
 | 
				
			||||||
 | 
					const assert = require("assert")
 | 
				
			||||||
 | 
					const {messageToEvent} = require("./message-to-event")
 | 
				
			||||||
 | 
					const data = require("../../test/data")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("message2event: stickers", async t => {
 | 
				
			||||||
 | 
					   const events = await messageToEvent(data.message.sticker)
 | 
				
			||||||
 | 
					   t.deepEqual(events, [{
 | 
				
			||||||
 | 
					      $type: "m.room.message",
 | 
				
			||||||
 | 
					      msgtype: "m.text",
 | 
				
			||||||
 | 
					      body: "can have attachments too"
 | 
				
			||||||
 | 
					   }, {
 | 
				
			||||||
 | 
					      $type: "m.room.message",
 | 
				
			||||||
 | 
					      msgtype: "m.image",
 | 
				
			||||||
 | 
					      url: "mxc://cadence.moe/ZDCNYnkPszxGKgObUIFmvjus",
 | 
				
			||||||
 | 
					      body: "image.png",
 | 
				
			||||||
 | 
					      external_url: "https://cdn.discordapp.com/attachments/122155380120748034/1106366167486038016/image.png",
 | 
				
			||||||
 | 
					      info: {
 | 
				
			||||||
 | 
					         mimetype: "image/png",
 | 
				
			||||||
 | 
					         w: 333,
 | 
				
			||||||
 | 
					         h: 287,
 | 
				
			||||||
 | 
					         size: 127373,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					   }, {
 | 
				
			||||||
 | 
					      $type: "m.sticker",
 | 
				
			||||||
 | 
					      todo: "todo"
 | 
				
			||||||
 | 
					   }])
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,14 @@ function memberAvatar(guildID, user, member) {
 | 
				
			||||||
	return `/guilds/${guildID}/users/${user.id}/avatars/${member.avatar}.png?size=${IMAGE_SIZE}`
 | 
						return `/guilds/${guildID}/users/${user.id}/avatars/${member.avatar}.png?size=${IMAGE_SIZE}`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function emoji(emojiID, animated) {
 | 
				
			||||||
 | 
						const base = `/emojis/${emojiID}`
 | 
				
			||||||
 | 
						if (animated) return base + ".gif"
 | 
				
			||||||
 | 
						else return base + ".png"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.guildIcon = guildIcon
 | 
					module.exports.guildIcon = guildIcon
 | 
				
			||||||
module.exports.userAvatar = userAvatar
 | 
					module.exports.userAvatar = userAvatar
 | 
				
			||||||
module.exports.memberAvatar = memberAvatar
 | 
					module.exports.memberAvatar = memberAvatar
 | 
				
			||||||
 | 
					module.exports.emoji = emoji
 | 
				
			||||||
module.exports.uploadDiscordFileToMxc = uploadDiscordFileToMxc
 | 
					module.exports.uploadDiscordFileToMxc = uploadDiscordFileToMxc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										74
									
								
								test/data.js
									
										
									
									
									
								
							
							
						
						
									
										74
									
								
								test/data.js
									
										
									
									
									
								
							| 
						 | 
					@ -6,18 +6,18 @@ module.exports = {
 | 
				
			||||||
	channel: {
 | 
						channel: {
 | 
				
			||||||
		general: {
 | 
							general: {
 | 
				
			||||||
			type: 0,
 | 
								type: 0,
 | 
				
			||||||
			topic: 'https://docs.google.com/document/d/blah/edit | I spread, pipe, and whip because it is my will. :headstone:',
 | 
								topic: "https://docs.google.com/document/d/blah/edit | I spread, pipe, and whip because it is my will. :headstone:",
 | 
				
			||||||
			rate_limit_per_user: 0,
 | 
								rate_limit_per_user: 0,
 | 
				
			||||||
			position: 0,
 | 
								position: 0,
 | 
				
			||||||
			permission_overwrites: [],
 | 
								permission_overwrites: [],
 | 
				
			||||||
			parent_id: null,
 | 
								parent_id: null,
 | 
				
			||||||
			nsfw: false,
 | 
								nsfw: false,
 | 
				
			||||||
			name: 'collective-unconscious' ,
 | 
								name: "collective-unconscious" ,
 | 
				
			||||||
			last_pin_timestamp: '2023-04-06T09:51:57+00:00',
 | 
								last_pin_timestamp: "2023-04-06T09:51:57+00:00",
 | 
				
			||||||
			last_message_id: '1103832925784514580',
 | 
								last_message_id: "1103832925784514580",
 | 
				
			||||||
			id: '112760669178241024',
 | 
								id: "112760669178241024",
 | 
				
			||||||
			default_thread_rate_limit_per_user: 0,
 | 
								default_thread_rate_limit_per_user: 0,
 | 
				
			||||||
			guild_id: '112760669178241024'
 | 
								guild_id: "112760669178241024"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	room: {
 | 
						room: {
 | 
				
			||||||
| 
						 | 
					@ -45,41 +45,85 @@ module.exports = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	guild: {
 | 
						guild: {
 | 
				
			||||||
		general: {
 | 
							general: {
 | 
				
			||||||
			owner_id: '112760500130975744',
 | 
								owner_id: "112760500130975744",
 | 
				
			||||||
			premium_tier: 3,
 | 
								premium_tier: 3,
 | 
				
			||||||
			stickers: [],
 | 
								stickers: [],
 | 
				
			||||||
			max_members: 500000,
 | 
								max_members: 500000,
 | 
				
			||||||
			splash: '86a34ed02524b972918bef810087f8e7',
 | 
								splash: "86a34ed02524b972918bef810087f8e7",
 | 
				
			||||||
			explicit_content_filter: 0,
 | 
								explicit_content_filter: 0,
 | 
				
			||||||
			afk_channel_id: null,
 | 
								afk_channel_id: null,
 | 
				
			||||||
			nsfw_level: 0,
 | 
								nsfw_level: 0,
 | 
				
			||||||
			description: null,
 | 
								description: null,
 | 
				
			||||||
			preferred_locale: 'en-US',
 | 
								preferred_locale: "en-US",
 | 
				
			||||||
			system_channel_id: '112760669178241024',
 | 
								system_channel_id: "112760669178241024",
 | 
				
			||||||
			mfa_level: 0,
 | 
								mfa_level: 0,
 | 
				
			||||||
			/** @type {300} */
 | 
								/** @type {300} */
 | 
				
			||||||
			afk_timeout: 300,
 | 
								afk_timeout: 300,
 | 
				
			||||||
			id: '112760669178241024',
 | 
								id: "112760669178241024",
 | 
				
			||||||
			icon: 'a_f83622e09ead74f0c5c527fe241f8f8c',
 | 
								icon: "a_f83622e09ead74f0c5c527fe241f8f8c",
 | 
				
			||||||
			emojis: [],
 | 
								emojis: [],
 | 
				
			||||||
			premium_subscription_count: 14,
 | 
								premium_subscription_count: 14,
 | 
				
			||||||
			roles: [],
 | 
								roles: [],
 | 
				
			||||||
			discovery_splash: null,
 | 
								discovery_splash: null,
 | 
				
			||||||
			default_message_notifications: 1,
 | 
								default_message_notifications: 1,
 | 
				
			||||||
			region: 'deprecated',
 | 
								region: "deprecated",
 | 
				
			||||||
			max_video_channel_users: 25,
 | 
								max_video_channel_users: 25,
 | 
				
			||||||
			verification_level: 0,
 | 
								verification_level: 0,
 | 
				
			||||||
			application_id: null,
 | 
								application_id: null,
 | 
				
			||||||
			premium_progress_bar_enabled: false,
 | 
								premium_progress_bar_enabled: false,
 | 
				
			||||||
			banner: 'a_a666ae551605a2d8cda0afd591c0af3a',
 | 
								banner: "a_a666ae551605a2d8cda0afd591c0af3a",
 | 
				
			||||||
			features: [],
 | 
								features: [],
 | 
				
			||||||
			vanity_url_code: null,
 | 
								vanity_url_code: null,
 | 
				
			||||||
			hub_type: null,
 | 
								hub_type: null,
 | 
				
			||||||
			public_updates_channel_id: null,
 | 
								public_updates_channel_id: null,
 | 
				
			||||||
			rules_channel_id: null,
 | 
								rules_channel_id: null,
 | 
				
			||||||
			name: 'Psychonauts 3',
 | 
								name: "Psychonauts 3",
 | 
				
			||||||
			max_stage_video_channel_users: 300,
 | 
								max_stage_video_channel_users: 300,
 | 
				
			||||||
			system_channel_flags: 0|0
 | 
								system_channel_flags: 0|0
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						message: {
 | 
				
			||||||
 | 
							// Display order is text content, attachments, then stickers
 | 
				
			||||||
 | 
							sticker: {
 | 
				
			||||||
 | 
								id: "1106366167788044450",
 | 
				
			||||||
 | 
								type: 0,
 | 
				
			||||||
 | 
								content: "can have attachments too",
 | 
				
			||||||
 | 
								channel_id: "122155380120748034",
 | 
				
			||||||
 | 
								author: {
 | 
				
			||||||
 | 
									id: "113340068197859328",
 | 
				
			||||||
 | 
									username: "Cookie 🍪",
 | 
				
			||||||
 | 
									global_name: null,
 | 
				
			||||||
 | 
									display_name: null,
 | 
				
			||||||
 | 
									avatar: "b48302623a12bc7c59a71328f72ccb39",
 | 
				
			||||||
 | 
									discriminator: "7766",
 | 
				
			||||||
 | 
									public_flags: 128,
 | 
				
			||||||
 | 
									avatar_decoration: null
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								attachments: [{
 | 
				
			||||||
 | 
									id: "1106366167486038016",
 | 
				
			||||||
 | 
									filename: "image.png",
 | 
				
			||||||
 | 
									size: 127373,
 | 
				
			||||||
 | 
									url: "https://cdn.discordapp.com/attachments/122155380120748034/1106366167486038016/image.png",
 | 
				
			||||||
 | 
									proxy_url: "https://media.discordapp.net/attachments/122155380120748034/1106366167486038016/image.png",
 | 
				
			||||||
 | 
									width: 333,
 | 
				
			||||||
 | 
									height: 287,
 | 
				
			||||||
 | 
									content_type: "image/png"
 | 
				
			||||||
 | 
								}],
 | 
				
			||||||
 | 
								embeds: [],
 | 
				
			||||||
 | 
								mentions: [],
 | 
				
			||||||
 | 
								mention_roles: [],
 | 
				
			||||||
 | 
								pinned: false,
 | 
				
			||||||
 | 
								mention_everyone: false,
 | 
				
			||||||
 | 
								tts: false,
 | 
				
			||||||
 | 
								timestamp: "2023-05-11T23:44:09.690000+00:00",
 | 
				
			||||||
 | 
								edited_timestamp: null,
 | 
				
			||||||
 | 
								flags: 0,
 | 
				
			||||||
 | 
								components: [],
 | 
				
			||||||
 | 
								sticker_items: [{
 | 
				
			||||||
 | 
									id: "1106323941183717586",
 | 
				
			||||||
 | 
									format_type: 1,
 | 
				
			||||||
 | 
									name: "pomu puff"
 | 
				
			||||||
 | 
								}]
 | 
				
			||||||
 | 
							 }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,5 +14,6 @@ Object.assign(passthrough, { config, sync, db })
 | 
				
			||||||
require("../matrix/kstate.test")
 | 
					require("../matrix/kstate.test")
 | 
				
			||||||
require("../matrix/api.test")
 | 
					require("../matrix/api.test")
 | 
				
			||||||
require("../matrix/read-registration.test")
 | 
					require("../matrix/read-registration.test")
 | 
				
			||||||
 | 
					require("../d2m/converters/message-to-event.test")
 | 
				
			||||||
require("../d2m/actions/create-room.test")
 | 
					require("../d2m/actions/create-room.test")
 | 
				
			||||||
require("../d2m/converters/user-to-mxid.test")
 | 
					require("../d2m/converters/user-to-mxid.test")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue