2023-04-25 20:06:08 +00:00
// @ts-check
2023-06-28 12:06:56 +00:00
const assert = require ( "assert" ) . strict
2023-04-25 20:06:08 +00:00
const markdown = require ( "discord-markdown" )
2023-05-12 05:35:37 +00:00
const passthrough = require ( "../../passthrough" )
2023-06-28 12:06:56 +00:00
const { sync , db , discord } = passthrough
2023-05-12 05:35:37 +00:00
/** @type {import("../../matrix/file")} */
const file = sync . require ( "../../matrix/file" )
2023-07-07 05:31:39 +00:00
function getDiscordParseCallbacks ( message , useHTML ) {
return {
user : node => {
const mxid = db . prepare ( "SELECT mxid FROM sim WHERE discord_id = ?" ) . pluck ( ) . get ( node . id )
const username = message . mentions . find ( ment => ment . id === node . id ) ? . username || node . id
if ( mxid && useHTML ) {
return ` <a href="https://matrix.to/#/ ${ mxid } ">@ ${ username } </a> `
} else {
return ` @ ${ username } : `
}
} ,
channel : node => {
2023-07-10 22:10:47 +00:00
const { room _id , name , nick } = db . prepare ( "SELECT room_id, name, nick FROM channel_room WHERE channel_id = ?" ) . get ( node . id )
if ( room _id && useHTML ) {
return ` <a href="https://matrix.to/#/ ${ room _id } "># ${ nick || name } </a> `
2023-07-07 05:31:39 +00:00
} else {
2023-07-10 22:10:47 +00:00
return ` # ${ nick || name } `
2023-07-07 05:31:39 +00:00
}
} ,
role : node =>
"@&" + node . id ,
everyone : node =>
"@room" ,
here : node =>
"@here"
}
}
2023-04-25 20:06:08 +00:00
/ * *
* @ param { import ( "discord-api-types/v10" ) . APIMessage } message
2023-06-28 12:06:56 +00:00
* @ param { import ( "discord-api-types/v10" ) . APIGuild } guild
2023-04-25 20:06:08 +00:00
* /
2023-06-28 12:06:56 +00:00
async function messageToEvent ( message , guild ) {
2023-05-12 05:35:37 +00:00
const events = [ ]
// Text content appears first
2023-07-01 13:41:31 +00:00
if ( message . content ) {
2023-07-10 20:01:11 +00:00
let content = message . content
content = content . replace ( /https:\/\/(?:ptb\.|canary\.|www\.)?discord(?:app)?\.com\/channels\/([0-9]+)\/([0-9]+)\/([0-9]+)/ , ( whole , guildID , channelID , messageID ) => {
const row = db . prepare ( "SELECT room_id, event_id FROM event_message INNER JOIN channel_room USING (channel_id) WHERE channel_id = ? AND message_id = ? AND part = 0" ) . get ( channelID , messageID )
if ( row ) {
return ` https://matrix.to/#/ ${ row . room _id } / ${ row . event _id } `
} else {
return ` ${ whole } [event not found] `
}
} )
const html = markdown . toHTML ( content , {
2023-07-07 05:31:39 +00:00
discordCallback : getDiscordParseCallbacks ( message , true )
2023-07-01 13:41:31 +00:00
} , null , null )
2023-07-07 05:31:39 +00:00
2023-07-10 20:01:11 +00:00
const body = markdown . toHTML ( content , {
discordCallback : getDiscordParseCallbacks ( message , false ) ,
2023-07-07 05:31:39 +00:00
discordOnly : true ,
escapeHTML : false ,
} , null , null )
2023-07-01 13:41:31 +00:00
const isPlaintext = body === html
2023-07-07 05:31:39 +00:00
2023-07-01 13:41:31 +00:00
if ( isPlaintext ) {
events . push ( {
$type : "m.room.message" ,
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
} )
2023-05-12 05:35:37 +00:00
}
2023-04-25 20:06:08 +00:00
}
2023-05-12 05:35:37 +00:00
// 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
2023-06-28 12:06:56 +00:00
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 )
}
2023-05-12 05:35:37 +00:00
return events
2023-04-25 20:06:08 +00:00
}
2023-05-05 05:29:08 +00:00
2023-05-08 11:37:51 +00:00
module . exports . messageToEvent = messageToEvent