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
|
||||||
msgtype: "m.text",
|
if (isPlaintext) {
|
||||||
body: body,
|
events.push({
|
||||||
format: "org.matrix.custom.html",
|
$type: "m.room.message",
|
||||||
formatted_body: html
|
msgtype: "m.text",
|
||||||
|
body: body
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
events.push({
|
||||||
|
$type: "m.room.message",
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: body,
|
||||||
|
format: "org.matrix.custom.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…
Reference in a new issue