support d->m stickers
This commit is contained in:
		
							parent
							
								
									584f19a011
								
							
						
					
					
						commit
						740ddc36d1
					
				
					 7 changed files with 67 additions and 18 deletions
				
			
		| 
						 | 
					@ -32,12 +32,13 @@ function applyKStateDiffToRoom(roomID, kstate) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIGuildTextChannel} channel
 | 
					 * @param {DiscordTypes.APIGuildTextChannel} channel
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIGuild} guild
 | 
					 * @param {DiscordTypes.APIGuild} guild
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
async function channelToKState(channel, guild) {
 | 
					async function channelToKState(channel, guild) {
 | 
				
			||||||
	const spaceID = db.prepare("SELECT space_id FROM guild_space WHERE guild_id = ?").pluck().get(guild.id)
 | 
						const spaceID = db.prepare("SELECT space_id FROM guild_space WHERE guild_id = ?").pluck().get(guild.id)
 | 
				
			||||||
	assert.ok(typeof spaceID === "string")
 | 
						assert.ok(typeof spaceID === "string")
 | 
				
			||||||
 | 
						const customName = db.prepare("SELECT nick FROM channel_room WHERE channel_id = ?").pluck().get(channel.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const avatarEventContent = {}
 | 
						const avatarEventContent = {}
 | 
				
			||||||
	if (guild.icon) {
 | 
						if (guild.icon) {
 | 
				
			||||||
| 
						 | 
					@ -45,9 +46,27 @@ async function channelToKState(channel, guild) {
 | 
				
			||||||
		avatarEventContent.url = await file.uploadDiscordFileToMxc(avatarEventContent.discord_path) // TODO: somehow represent future values in kstate (callbacks?), while still allowing for diffing, so test cases don't need to touch the media API
 | 
							avatarEventContent.url = await file.uploadDiscordFileToMxc(avatarEventContent.discord_path) // TODO: somehow represent future values in kstate (callbacks?), while still allowing for diffing, so test cases don't need to touch the media API
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: Improve nasty nested ifs
 | 
				
			||||||
 | 
						let convertedName, convertedTopic
 | 
				
			||||||
 | 
						if (customName) {
 | 
				
			||||||
 | 
							convertedName = customName
 | 
				
			||||||
 | 
							if (channel.topic) {
 | 
				
			||||||
 | 
								convertedTopic = `${channel.name} | ${channel.topic}\n\nChannel ID: ${channel.id}\nGuild ID: ${guild.id}`
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								convertedTopic = `${channel.name}\n\nChannel ID: ${channel.id}\nGuild ID: ${guild.id}`
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							convertedName = channel.name
 | 
				
			||||||
 | 
							if (channel.topic) {
 | 
				
			||||||
 | 
								convertedTopic = `${channel.topic}\n\nChannel ID: ${channel.id}\nGuild ID: ${guild.id}`
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								convertedTopic = `Channel ID: ${channel.id}\nGuild ID: ${guild.id}`
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const channelKState = {
 | 
						const channelKState = {
 | 
				
			||||||
		"m.room.name/": {name: channel.name},
 | 
							"m.room.name/": {name: convertedName},
 | 
				
			||||||
		"m.room.topic/": {$if: channel.topic, topic: channel.topic},
 | 
							"m.room.topic/": {topic: convertedTopic},
 | 
				
			||||||
		"m.room.avatar/": avatarEventContent,
 | 
							"m.room.avatar/": avatarEventContent,
 | 
				
			||||||
		"m.room.guest_access/": {guest_access: "can_join"},
 | 
							"m.room.guest_access/": {guest_access: "can_join"},
 | 
				
			||||||
		"m.room.history_visibility/": {history_visibility: "invited"},
 | 
							"m.room.history_visibility/": {history_visibility: "invited"},
 | 
				
			||||||
| 
						 | 
					@ -69,7 +88,7 @@ async function channelToKState(channel, guild) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Create a bridge room, store the relationship in the database, and add it to the guild's space.
 | 
					 * Create a bridge room, store the relationship in the database, and add it to the guild's space.
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIGuildTextChannel} channel
 | 
					 * @param {DiscordTypes.APIGuildTextChannel} channel
 | 
				
			||||||
 * @param guild
 | 
					 * @param guild
 | 
				
			||||||
 * @param {string} spaceID
 | 
					 * @param {string} spaceID
 | 
				
			||||||
 * @param {any} kstate
 | 
					 * @param {any} kstate
 | 
				
			||||||
| 
						 | 
					@ -96,7 +115,7 @@ async function createRoom(channel, guild, spaceID, kstate) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIGuildChannel} channel
 | 
					 * @param {DiscordTypes.APIGuildChannel} channel
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function channelToGuild(channel) {
 | 
					function channelToGuild(channel) {
 | 
				
			||||||
	const guildID = channel.guild_id
 | 
						const guildID = channel.guild_id
 | 
				
			||||||
| 
						 | 
					@ -129,7 +148,7 @@ function channelToGuild(channel) {
 | 
				
			||||||
 * @returns {Promise<string>} room ID
 | 
					 * @returns {Promise<string>} room ID
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
async function _syncRoom(channelID, shouldActuallySync) {
 | 
					async function _syncRoom(channelID, shouldActuallySync) {
 | 
				
			||||||
	/** @ts-ignore @type {import("discord-api-types/v10").APIGuildChannel} */
 | 
						/** @ts-ignore @type {DiscordTypes.APIGuildChannel} */
 | 
				
			||||||
	const channel = discord.channels.get(channelID)
 | 
						const channel = discord.channels.get(channelID)
 | 
				
			||||||
	assert.ok(channel)
 | 
						assert.ok(channel)
 | 
				
			||||||
	const guild = channelToGuild(channel)
 | 
						const guild = channelToGuild(channel)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ async function sendMessage(message, guild) {
 | 
				
			||||||
		await registerUser.syncUser(message.author, message.member, message.guild_id, roomID)
 | 
							await registerUser.syncUser(message.author, message.member, message.guild_id, roomID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const events = await messageToEvent.messageToEvent(message)
 | 
						const events = await messageToEvent.messageToEvent(message, guild)
 | 
				
			||||||
	const eventIDs = []
 | 
						const eventIDs = []
 | 
				
			||||||
	let eventPart = 0 // 0 is primary, 1 is supporting
 | 
						let eventPart = 0 // 0 is primary, 1 is supporting
 | 
				
			||||||
	for (const event of events) {
 | 
						for (const event of events) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,18 @@
 | 
				
			||||||
// @ts-check
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const assert = require("assert").strict
 | 
				
			||||||
const markdown = require("discord-markdown")
 | 
					const markdown = require("discord-markdown")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const passthrough = require("../../passthrough")
 | 
					const passthrough = require("../../passthrough")
 | 
				
			||||||
const { sync, db } = passthrough
 | 
					const { sync, db, discord } = passthrough
 | 
				
			||||||
/** @type {import("../../matrix/file")} */
 | 
					/** @type {import("../../matrix/file")} */
 | 
				
			||||||
const file = sync.require("../../matrix/file")
 | 
					const file = sync.require("../../matrix/file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {import("discord-api-types/v10").APIMessage} message
 | 
					 * @param {import("discord-api-types/v10").APIMessage} message
 | 
				
			||||||
 | 
					 * @param {import("discord-api-types/v10").APIGuild} guild
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
async function messageToEvent(message) {
 | 
					async function messageToEvent(message, guild) {
 | 
				
			||||||
	const events = []
 | 
						const events = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Text content appears first
 | 
						// Text content appears first
 | 
				
			||||||
| 
						 | 
					@ -87,6 +89,31 @@ async function messageToEvent(message) {
 | 
				
			||||||
	events.push(...attachmentEvents)
 | 
						events.push(...attachmentEvents)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Then stickers
 | 
						// Then stickers
 | 
				
			||||||
 | 
						if (message.sticker_items) {
 | 
				
			||||||
 | 
							const stickerEvents = await Promise.all(message.sticker_items.map(async stickerItem => {
 | 
				
			||||||
 | 
								const format = file.stickerFormat.get(stickerItem.format_type)
 | 
				
			||||||
 | 
								if (format?.mime) {
 | 
				
			||||||
 | 
									let body = stickerItem.name
 | 
				
			||||||
 | 
									const sticker = guild.stickers.find(sticker => sticker.id === stickerItem.id)
 | 
				
			||||||
 | 
									if (sticker && sticker.description) body += ` - ${sticker.description}`
 | 
				
			||||||
 | 
									return {
 | 
				
			||||||
 | 
										$type: "m.sticker",
 | 
				
			||||||
 | 
										body,
 | 
				
			||||||
 | 
										info: {
 | 
				
			||||||
 | 
											mimetype: format.mime
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										url: await file.uploadDiscordFileToMxc(file.sticker(stickerItem))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return {
 | 
				
			||||||
 | 
										$type: "m.room.message",
 | 
				
			||||||
 | 
										msgtype: "m.text",
 | 
				
			||||||
 | 
										body: "Unsupported sticker format. Name: " + stickerItem.name
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
							events.push(...stickerEvents)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return events
 | 
						return events
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ const {messageToEvent} = require("./message-to-event")
 | 
				
			||||||
const data = require("../../test/data")
 | 
					const data = require("../../test/data")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("message2event: stickers", async t => {
 | 
					test("message2event: stickers", async t => {
 | 
				
			||||||
   const events = await messageToEvent(data.message.sticker)
 | 
					   const events = await messageToEvent(data.message.sticker, data.guild.general)
 | 
				
			||||||
   t.deepEqual(events, [{
 | 
					   t.deepEqual(events, [{
 | 
				
			||||||
      $type: "m.room.message",
 | 
					      $type: "m.room.message",
 | 
				
			||||||
      msgtype: "m.text",
 | 
					      msgtype: "m.text",
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,6 @@ test("message2event: stickers", async t => {
 | 
				
			||||||
         // thumbnail_url
 | 
					         // thumbnail_url
 | 
				
			||||||
         // thumbnail_info
 | 
					         // thumbnail_info
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      url: "mxc://"
 | 
					      url: "mxc://cadence.moe/UuUaLwXhkxFRwwWCXipDlBHn"
 | 
				
			||||||
   }])
 | 
					   }])
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
// @ts-check
 | 
					const assert = require("assert").strict
 | 
				
			||||||
 | 
					 | 
				
			||||||
const {sync} = require("../passthrough")
 | 
					const {sync} = require("../passthrough")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {import("./actions/send-message")}) */
 | 
					/** @type {import("./actions/send-message")}) */
 | 
				
			||||||
| 
						 | 
					@ -15,8 +14,11 @@ module.exports = {
 | 
				
			||||||
	 * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
 | 
						 * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	onMessageCreate(client, message) {
 | 
						onMessageCreate(client, message) {
 | 
				
			||||||
 | 
							/** @ts-ignore @type {import("discord-api-types/v10").APIGuildChannel} */
 | 
				
			||||||
 | 
							const channel = client.channels.get(message.channel_id)
 | 
				
			||||||
 | 
							const guild = client.guilds.get(channel.guild_id)
 | 
				
			||||||
		if (message.guild_id !== "112760669178241024") return // TODO: activate on other servers (requires the space creation flow to be done first)
 | 
							if (message.guild_id !== "112760669178241024") return // TODO: activate on other servers (requires the space creation flow to be done first)
 | 
				
			||||||
		sendMessage.sendMessage(message)
 | 
							sendMessage.sendMessage(message, guild)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,10 +83,11 @@ function emoji(emojiID, animated) {
 | 
				
			||||||
const stickerFormat = new Map([
 | 
					const stickerFormat = new Map([
 | 
				
			||||||
	[1, {label: "PNG", ext: "png", mime: "image/png"}],
 | 
						[1, {label: "PNG", ext: "png", mime: "image/png"}],
 | 
				
			||||||
	[2, {label: "APNG", ext: "png", mime: "image/apng"}],
 | 
						[2, {label: "APNG", ext: "png", mime: "image/apng"}],
 | 
				
			||||||
	[3, {label: "LOTTIE", ext: "json", mime: "application/json"}],
 | 
						[3, {label: "LOTTIE", ext: "json", mime: null}],
 | 
				
			||||||
	[4, {label: "GIF", ext: "gif", mime: "image/gif"}]
 | 
						[4, {label: "GIF", ext: "gif", mime: "image/gif"}]
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @param {{id: string, format_type: number}} sticker */
 | 
				
			||||||
function sticker(sticker) {
 | 
					function sticker(sticker) {
 | 
				
			||||||
	const format = stickerFormat.get(sticker.format_type)
 | 
						const format = stickerFormat.get(sticker.format_type)
 | 
				
			||||||
	if (!format) throw new Error(`No such format ${sticker.format_type} for sticker ${JSON.stringify(sticker)}`)
 | 
						if (!format) throw new Error(`No such format ${sticker.format_type} for sticker ${JSON.stringify(sticker)}`)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,8 +22,8 @@ module.exports = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	room: {
 | 
						room: {
 | 
				
			||||||
		general: {
 | 
							general: {
 | 
				
			||||||
			"m.room.name/": {name: "collective-unconscious"},
 | 
								"m.room.name/": {name: "main"},
 | 
				
			||||||
			"m.room.topic/": {topic: "https://docs.google.com/document/d/blah/edit | I spread, pipe, and whip because it is my will. :headstone:"},
 | 
								"m.room.topic/": {topic: "collective-unconscious | https://docs.google.com/document/d/blah/edit | I spread, pipe, and whip because it is my will. :headstone:\n\nChannel ID: 112760669178241024\nGuild ID: 112760669178241024"},
 | 
				
			||||||
			"m.room.guest_access/": {guest_access: "can_join"},
 | 
								"m.room.guest_access/": {guest_access: "can_join"},
 | 
				
			||||||
			"m.room.history_visibility/": {history_visibility: "invited"},
 | 
								"m.room.history_visibility/": {history_visibility: "invited"},
 | 
				
			||||||
			"m.space.parent/!jjWAGMeQdNrVZSSfvz:cadence.moe": {
 | 
								"m.space.parent/!jjWAGMeQdNrVZSSfvz:cadence.moe": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue