Compare commits
No commits in common. "8026cf0cad28e3b77bb4f3ac4781819f3baff9cb" and "4871410a30c14200951f65bb7d888108c148c438" have entirely different histories.
8026cf0cad
...
4871410a30
5 changed files with 98 additions and 264 deletions
|
@ -86,103 +86,6 @@ const embedTitleParser = markdown.markdownEngine.parserFor({
|
||||||
link: undefined
|
link: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {{room?: boolean, user_ids?: string[]}} mentions
|
|
||||||
* @param {DiscordTypes.APIAttachment} attachment
|
|
||||||
*/
|
|
||||||
async function attachmentToEvent(mentions, attachment) {
|
|
||||||
const emoji =
|
|
||||||
attachment.content_type?.startsWith("image/jp") ? "📸"
|
|
||||||
: attachment.content_type?.startsWith("image/") ? "🖼️"
|
|
||||||
: attachment.content_type?.startsWith("video/") ? "🎞️"
|
|
||||||
: 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: `<blockquote>${emoji} Uploaded SPOILER file: <a href="${attachment.url}"><span data-mx-spoiler>${attachment.url}</span></a> (${pb(attachment.size)})</blockquote>`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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) {
|
|
||||||
return {
|
|
||||||
$type: "m.room.message",
|
|
||||||
"m.mentions": mentions,
|
|
||||||
msgtype: "m.text",
|
|
||||||
body: `${emoji} Uploaded file: ${attachment.url} (${pb(attachment.size)})`,
|
|
||||||
format: "org.matrix.custom.html",
|
|
||||||
formatted_body: `${emoji} Uploaded file: <a href="${attachment.url}">${attachment.filename}</a> (${pb(attachment.size)})`
|
|
||||||
}
|
|
||||||
} else if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) {
|
|
||||||
return {
|
|
||||||
$type: "m.room.message",
|
|
||||||
"m.mentions": mentions,
|
|
||||||
msgtype: "m.image",
|
|
||||||
url: await file.uploadDiscordFileToMxc(attachment.url),
|
|
||||||
external_url: attachment.url,
|
|
||||||
body: attachment.filename,
|
|
||||||
filename: attachment.filename,
|
|
||||||
info: {
|
|
||||||
mimetype: attachment.content_type,
|
|
||||||
w: attachment.width,
|
|
||||||
h: attachment.height,
|
|
||||||
size: attachment.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (attachment.content_type?.startsWith("video/") && attachment.width && attachment.height) {
|
|
||||||
return {
|
|
||||||
$type: "m.room.message",
|
|
||||||
"m.mentions": mentions,
|
|
||||||
msgtype: "m.video",
|
|
||||||
url: await file.uploadDiscordFileToMxc(attachment.url),
|
|
||||||
external_url: attachment.url,
|
|
||||||
body: attachment.description || attachment.filename,
|
|
||||||
filename: attachment.filename,
|
|
||||||
info: {
|
|
||||||
mimetype: attachment.content_type,
|
|
||||||
w: attachment.width,
|
|
||||||
h: attachment.height,
|
|
||||||
size: attachment.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (attachment.content_type?.startsWith("audio/")) {
|
|
||||||
return {
|
|
||||||
$type: "m.room.message",
|
|
||||||
"m.mentions": mentions,
|
|
||||||
msgtype: "m.audio",
|
|
||||||
url: await file.uploadDiscordFileToMxc(attachment.url),
|
|
||||||
external_url: attachment.url,
|
|
||||||
body: attachment.description || attachment.filename,
|
|
||||||
filename: attachment.filename,
|
|
||||||
info: {
|
|
||||||
mimetype: attachment.content_type,
|
|
||||||
size: attachment.size,
|
|
||||||
duration: attachment.duration_secs ? attachment.duration_secs * 1000 : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
$type: "m.room.message",
|
|
||||||
"m.mentions": mentions,
|
|
||||||
msgtype: "m.file",
|
|
||||||
url: await file.uploadDiscordFileToMxc(attachment.url),
|
|
||||||
external_url: attachment.url,
|
|
||||||
body: attachment.filename,
|
|
||||||
filename: attachment.filename,
|
|
||||||
info: {
|
|
||||||
mimetype: attachment.content_type,
|
|
||||||
size: attachment.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("discord-api-types/v10").APIMessage} message
|
* @param {import("discord-api-types/v10").APIMessage} message
|
||||||
* @param {import("discord-api-types/v10").APIGuild} guild
|
* @param {import("discord-api-types/v10").APIGuild} guild
|
||||||
|
@ -413,7 +316,98 @@ async function messageToEvent(message, guild, options = {}, di) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then attachments
|
// Then attachments
|
||||||
const attachmentEvents = await Promise.all(message.attachments.map(attachmentToEvent.bind(null, mentions)))
|
const attachmentEvents = await Promise.all(message.attachments.map(async attachment => {
|
||||||
|
const emoji =
|
||||||
|
attachment.content_type?.startsWith("image/jp") ? "📸"
|
||||||
|
: attachment.content_type?.startsWith("image/") ? "🖼️"
|
||||||
|
: attachment.content_type?.startsWith("video/") ? "🎞️"
|
||||||
|
: 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: `<blockquote>${emoji} Uploaded SPOILER file: <a href="${attachment.url}"><span data-mx-spoiler>${attachment.url}</span></a> (${pb(attachment.size)})</blockquote>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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) {
|
||||||
|
return {
|
||||||
|
$type: "m.room.message",
|
||||||
|
"m.mentions": mentions,
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: `${emoji} Uploaded file: ${attachment.url} (${pb(attachment.size)})`,
|
||||||
|
format: "org.matrix.custom.html",
|
||||||
|
formatted_body: `${emoji} Uploaded file: <a href="${attachment.url}">${attachment.filename}</a> (${pb(attachment.size)})`
|
||||||
|
}
|
||||||
|
} else if (attachment.content_type?.startsWith("image/") && attachment.width && attachment.height) {
|
||||||
|
return {
|
||||||
|
$type: "m.room.message",
|
||||||
|
"m.mentions": mentions,
|
||||||
|
msgtype: "m.image",
|
||||||
|
url: await file.uploadDiscordFileToMxc(attachment.url),
|
||||||
|
external_url: attachment.url,
|
||||||
|
body: attachment.filename,
|
||||||
|
filename: attachment.filename,
|
||||||
|
info: {
|
||||||
|
mimetype: attachment.content_type,
|
||||||
|
w: attachment.width,
|
||||||
|
h: attachment.height,
|
||||||
|
size: attachment.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (attachment.content_type?.startsWith("video/") && attachment.width && attachment.height) {
|
||||||
|
return {
|
||||||
|
$type: "m.room.message",
|
||||||
|
"m.mentions": mentions,
|
||||||
|
msgtype: "m.video",
|
||||||
|
url: await file.uploadDiscordFileToMxc(attachment.url),
|
||||||
|
external_url: attachment.url,
|
||||||
|
body: attachment.description || attachment.filename,
|
||||||
|
filename: attachment.filename,
|
||||||
|
info: {
|
||||||
|
mimetype: attachment.content_type,
|
||||||
|
w: attachment.width,
|
||||||
|
h: attachment.height,
|
||||||
|
size: attachment.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (attachment.content_type?.startsWith("audio/")) {
|
||||||
|
return {
|
||||||
|
$type: "m.room.message",
|
||||||
|
"m.mentions": mentions,
|
||||||
|
msgtype: "m.audio",
|
||||||
|
url: await file.uploadDiscordFileToMxc(attachment.url),
|
||||||
|
external_url: attachment.url,
|
||||||
|
body: attachment.description || attachment.filename,
|
||||||
|
filename: attachment.filename,
|
||||||
|
info: {
|
||||||
|
mimetype: attachment.content_type,
|
||||||
|
size: attachment.size,
|
||||||
|
duration: attachment.duration_secs ? attachment.duration_secs * 1000 : undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
$type: "m.room.message",
|
||||||
|
"m.mentions": mentions,
|
||||||
|
msgtype: "m.file",
|
||||||
|
url: await file.uploadDiscordFileToMxc(attachment.url),
|
||||||
|
external_url: attachment.url,
|
||||||
|
body: attachment.filename,
|
||||||
|
filename: attachment.filename,
|
||||||
|
info: {
|
||||||
|
mimetype: attachment.content_type,
|
||||||
|
size: attachment.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
events.push(...attachmentEvents)
|
events.push(...attachmentEvents)
|
||||||
|
|
||||||
// Then embeds
|
// Then embeds
|
||||||
|
|
|
@ -73,7 +73,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
|
// 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, snow: discord.snow})
|
let {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api})
|
||||||
|
|
||||||
messagesToEdit = await Promise.all(messagesToEdit.map(async e => {
|
messagesToEdit = await Promise.all(messagesToEdit.map(async e => {
|
||||||
e.message = await resolvePendingFiles(e.message)
|
e.message = await resolvePendingFiles(e.message)
|
||||||
|
|
|
@ -122,7 +122,7 @@ turndownService.addRule("listItem", {
|
||||||
if (parent.nodeName === "OL") {
|
if (parent.nodeName === "OL") {
|
||||||
var start = parent.getAttribute("start")
|
var start = parent.getAttribute("start")
|
||||||
var index = Array.prototype.indexOf.call(parent.children, node)
|
var index = Array.prototype.indexOf.call(parent.children, node)
|
||||||
prefix = (start ? Number(start) + index : index + 1) + ". "
|
prefix = (start ? Number(start) + index : index + 1) + ". "
|
||||||
}
|
}
|
||||||
return prefix + content + (node.nextSibling && !/\n$/.test(content) ? "\n" : "")
|
return prefix + content + (node.nextSibling && !/\n$/.test(content) ? "\n" : "")
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ async function uploadEndOfMessageSpriteSheet(content, attachments, pendingFiles)
|
||||||
/**
|
/**
|
||||||
* @param {Ty.Event.Outer_M_Room_Message | Ty.Event.Outer_M_Room_Message_File | Ty.Event.Outer_M_Sticker | Ty.Event.Outer_M_Room_Message_Encrypted_File} event
|
* @param {Ty.Event.Outer_M_Room_Message | Ty.Event.Outer_M_Room_Message_File | Ty.Event.Outer_M_Sticker | Ty.Event.Outer_M_Room_Message_Encrypted_File} event
|
||||||
* @param {import("discord-api-types/v10").APIGuild} guild
|
* @param {import("discord-api-types/v10").APIGuild} guild
|
||||||
* @param {{api: import("../../matrix/api"), snow: import("snowtransfer").SnowTransfer}} di simple-as-nails dependency injection for the matrix API
|
* @param {{api: import("../../matrix/api")}} di simple-as-nails dependency injection for the matrix API
|
||||||
*/
|
*/
|
||||||
async function eventToMessage(event, guild, di) {
|
async function eventToMessage(event, guild, di) {
|
||||||
/** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[]})[]} */
|
/** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer | Readable}[]})[]} */
|
||||||
|
@ -289,8 +289,6 @@ async function eventToMessage(event, guild, di) {
|
||||||
const attachments = []
|
const attachments = []
|
||||||
/** @type {({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer})[]} */
|
/** @type {({name: string, url: string} | {name: string, url: string, key: string, iv: string} | {name: string, buffer: Buffer})[]} */
|
||||||
const pendingFiles = []
|
const pendingFiles = []
|
||||||
/** @type {DiscordTypes.APIUser[]} */
|
|
||||||
const ensureJoined = []
|
|
||||||
|
|
||||||
// Convert content depending on what the message is
|
// 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.type === "m.room.message" && (event.content.msgtype === "m.text" || event.content.msgtype === "m.emote")) {
|
||||||
|
@ -504,17 +502,6 @@ async function eventToMessage(event, guild, di) {
|
||||||
|
|
||||||
content = displayNameRunoff + replyLine + content
|
content = displayNameRunoff + replyLine + content
|
||||||
|
|
||||||
// Handling written @mentions: we need to look for candidate Discord members to join to the room
|
|
||||||
let writtenMentionMatch = content.match(/(?:^|[^"<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // d flag requires Node 16+
|
|
||||||
if (writtenMentionMatch) {
|
|
||||||
const results = await di.snow.guild.searchGuildMembers(guild.id, {query: writtenMentionMatch[1]})
|
|
||||||
if (results[0]) {
|
|
||||||
assert(results[0].user)
|
|
||||||
content = content.slice(0, writtenMentionMatch.index) + `<@${results[0].user.id}>` + content.slice(writtenMentionMatch.index + writtenMentionMatch[0].length)
|
|
||||||
ensureJoined.push(results[0].user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split into 2000 character chunks
|
// Split into 2000 character chunks
|
||||||
const chunks = chunk(content, 2000)
|
const chunks = chunk(content, 2000)
|
||||||
messages = messages.concat(chunks.map(content => ({
|
messages = messages.concat(chunks.map(content => ({
|
||||||
|
@ -556,8 +543,7 @@ async function eventToMessage(event, guild, di) {
|
||||||
return {
|
return {
|
||||||
messagesToEdit,
|
messagesToEdit,
|
||||||
messagesToSend,
|
messagesToSend,
|
||||||
messagesToDelete: messageIDsToEdit,
|
messagesToDelete: messageIDsToEdit
|
||||||
ensureJoined
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,6 @@ test("event2message: body is used when there is no formatted_body", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -90,15 +89,8 @@ test("event2message: any markdown in body is escaped, except strikethrough", asy
|
||||||
unsigned: {
|
unsigned: {
|
||||||
age: 405299
|
age: 405299
|
||||||
}
|
}
|
||||||
}, {}, {
|
|
||||||
snow: {
|
|
||||||
guild: {
|
|
||||||
searchGuildMembers: () => []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -130,7 +122,6 @@ test("event2message: links in formatted body are not broken", async t => {
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -160,7 +151,6 @@ test("event2message: links in plaintext body are not broken", async t => {
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -191,7 +181,6 @@ test("event2message: basic html is converted to markdown", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -222,7 +211,6 @@ test("event2message: spoilers work", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -253,7 +241,6 @@ test("event2message: markdown syntax is escaped", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -284,7 +271,6 @@ test("event2message: html lines are bridged correctly", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -315,7 +301,6 @@ test("event2message: html lines are bridged correctly", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -347,7 +332,6 @@ test("event2message: whitespace is collapsed", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -380,7 +364,6 @@ test("event2message: lists are bridged correctly", async t => {
|
||||||
"room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
"room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -409,7 +392,6 @@ test("event2message: long messages are split", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -444,7 +426,6 @@ test("event2message: code blocks work", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -476,7 +457,6 @@ test("event2message: code block contents are formatted correctly and not escaped
|
||||||
"room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
"room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -507,7 +487,6 @@ test("event2message: quotes have an appropriate amount of whitespace", async t =
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -549,7 +528,6 @@ test("event2message: lists have appropriate line breaks", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -561,48 +539,6 @@ test("event2message: lists have appropriate line breaks", async t => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("event2message: ordered list start attribute works", async t => {
|
|
||||||
t.deepEqual(
|
|
||||||
await eventToMessage({
|
|
||||||
content: {
|
|
||||||
body: 'i am not certain what you mean by "already exists with as discord". my goals are\n' +
|
|
||||||
'1. bridgeing specific channels with existing matrix rooms\n' +
|
|
||||||
' 2. optionally maybe entire "servers"\n' +
|
|
||||||
'3. offering the bridge as a public service ',
|
|
||||||
format: 'org.matrix.custom.html',
|
|
||||||
formatted_body: '<p>i am not certain what you mean by "already exists with as discord". my goals are</p>\n' +
|
|
||||||
'<ol>\n' +
|
|
||||||
'<li>bridgeing specific channels with existing matrix rooms\n' +
|
|
||||||
'<ol start="2">\n' +
|
|
||||||
'<li>optionally maybe entire "servers"</li>\n' +
|
|
||||||
'</ol>\n' +
|
|
||||||
'</li>\n' +
|
|
||||||
'<li>offering the bridge as a public service</li>\n' +
|
|
||||||
'</ol>\n',
|
|
||||||
'm.mentions': {},
|
|
||||||
msgtype: 'm.text'
|
|
||||||
},
|
|
||||||
room_id: '!cBxtVRxDlZvSVhJXVK:cadence.moe',
|
|
||||||
sender: '@Milan:tchncs.de',
|
|
||||||
type: 'm.room.message',
|
|
||||||
}, {}, {
|
|
||||||
api: {
|
|
||||||
getStateEvent: async () => ({displayname: "Milan"})
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
|
||||||
messagesToEdit: [],
|
|
||||||
messagesToSend: [{
|
|
||||||
username: "Milan",
|
|
||||||
content: `i am not certain what you mean by "already exists with as discord". my goals are\n\n1. bridgeing specific channels with existing matrix rooms\n 2. optionally maybe entire "servers"\n2. offering the bridge as a public service`,
|
|
||||||
avatar_url: undefined
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("event2message: m.emote plaintext works", async t => {
|
test("event2message: m.emote plaintext works", async t => {
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
await eventToMessage({
|
await eventToMessage({
|
||||||
|
@ -620,7 +556,6 @@ test("event2message: m.emote plaintext works", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -651,7 +586,6 @@ test("event2message: m.emote markdown syntax is escaped", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -699,7 +633,6 @@ test("event2message: rich reply to a sim user", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -776,7 +709,6 @@ test("event2message: rich reply to an already-edited message will quote the new
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -824,7 +756,6 @@ test("event2message: should avoid using blockquote contents as reply preview in
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -910,7 +841,6 @@ test("event2message: should include a reply preview when message ends with a blo
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -991,7 +921,6 @@ test("event2message: should include a reply preview when replying to a descripti
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1041,7 +970,6 @@ test("event2message: entities are not escaped in main message or reply preview",
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1120,7 +1048,6 @@ test("event2message: editing a rich reply to a sim user", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [{
|
messagesToEdit: [{
|
||||||
id: "1144874214311067708",
|
id: "1144874214311067708",
|
||||||
|
@ -1175,7 +1102,6 @@ test("event2message: editing a plaintext body message", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [{
|
messagesToEdit: [{
|
||||||
id: "1145688633186193479",
|
id: "1145688633186193479",
|
||||||
|
@ -1227,7 +1153,6 @@ test("event2message: editing a plaintext message to be longer", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [{
|
messagesToEdit: [{
|
||||||
id: "1145688633186193479",
|
id: "1145688633186193479",
|
||||||
|
@ -1283,7 +1208,6 @@ test("event2message: editing a plaintext message to be shorter", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: ["1145688633186193481"],
|
messagesToDelete: ["1145688633186193481"],
|
||||||
messagesToEdit: [{
|
messagesToEdit: [{
|
||||||
id: "1145688633186193480",
|
id: "1145688633186193480",
|
||||||
|
@ -1341,7 +1265,6 @@ test("event2message: editing a formatted body message", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [{
|
messagesToEdit: [{
|
||||||
id: "1145688633186193479",
|
id: "1145688633186193479",
|
||||||
|
@ -1394,7 +1317,6 @@ test("event2message: rich reply to a matrix user's long message with formatting"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1454,7 +1376,6 @@ test("event2message: rich reply to an image", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1506,7 +1427,6 @@ test("event2message: rich reply to a spoiler should ensure the spoiler is hidden
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1558,7 +1478,6 @@ test("event2message: with layered rich replies, the preview should only be the r
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1589,7 +1508,6 @@ test("event2message: raw mentioning discord users in plaintext body works", asyn
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1620,7 +1538,6 @@ test("event2message: raw mentioning discord users in formatted body works", asyn
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1651,7 +1568,6 @@ test("event2message: mentioning discord users works", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1682,7 +1598,6 @@ test("event2message: mentioning matrix users works", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1713,7 +1628,6 @@ test("event2message: mentioning bridged rooms works", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1744,7 +1658,6 @@ test("event2message: colon after mentions is stripped", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1786,7 +1699,6 @@ test("event2message: caches the member if the member is not known", async t => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1831,7 +1743,6 @@ test("event2message: skips caching the member if the member does not exist, some
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1875,7 +1786,6 @@ test("event2message: overly long usernames are shifted into the message content"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1908,7 +1818,6 @@ test("event2message: overly long usernames are not treated specially when the ms
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1938,7 +1847,6 @@ test("event2message: text attachments work", async t => {
|
||||||
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -1973,7 +1881,6 @@ test("event2message: image attachments work", async t => {
|
||||||
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -2023,7 +1930,6 @@ test("event2message: encrypted image attachments work", async t => {
|
||||||
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -2068,7 +1974,6 @@ test("event2message: stickers work", async t => {
|
||||||
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -2097,7 +2002,6 @@ test("event2message: static emojis work", async t => {
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -2124,7 +2028,6 @@ test("event2message: animated emojis work", async t => {
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -2151,7 +2054,6 @@ test("event2message: unknown emojis in the middle are linked", async t => {
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
ensureJoined: [],
|
|
||||||
messagesToDelete: [],
|
messagesToDelete: [],
|
||||||
messagesToEdit: [],
|
messagesToEdit: [],
|
||||||
messagesToSend: [{
|
messagesToSend: [{
|
||||||
|
@ -2163,53 +2065,6 @@ test("event2message: unknown emojis in the middle are linked", async t => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("event2message: guessed @mentions may join members to mention", async t => {
|
|
||||||
let called = 0
|
|
||||||
const subtext = {
|
|
||||||
user: {
|
|
||||||
id: "321876634777218072",
|
|
||||||
username: "subtext",
|
|
||||||
discriminator: "0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.deepEqual(
|
|
||||||
await eventToMessage({
|
|
||||||
type: "m.room.message",
|
|
||||||
sender: "@cadence:cadence.moe",
|
|
||||||
content: {
|
|
||||||
msgtype: "m.text",
|
|
||||||
body: "@subtext: what food would you like to order?"
|
|
||||||
},
|
|
||||||
event_id: "$u5gSwSzv_ZQS3eM00mnTBCor8nx_A_AwuQz7e59PZk8",
|
|
||||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
|
||||||
}, {
|
|
||||||
id: "112760669178241024"
|
|
||||||
}, {
|
|
||||||
snow: {
|
|
||||||
guild: {
|
|
||||||
async searchGuildMembers(guildID, options) {
|
|
||||||
called++
|
|
||||||
t.equal(guildID, "112760669178241024")
|
|
||||||
t.deepEqual(options, {query: "subtext"})
|
|
||||||
return [subtext]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
messagesToDelete: [],
|
|
||||||
messagesToEdit: [],
|
|
||||||
messagesToSend: [{
|
|
||||||
username: "cadence [they]",
|
|
||||||
content: "<@321876634777218072> what food would you like to order?",
|
|
||||||
avatar_url: undefined
|
|
||||||
}],
|
|
||||||
ensureJoined: [subtext.user]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
t.equal(called, 1, "searchGuildMembers should be called once")
|
|
||||||
})
|
|
||||||
|
|
||||||
slow()("event2message: unknown emoji in the end is reuploaded as a sprite sheet", async t => {
|
slow()("event2message: unknown emoji in the end is reuploaded as a sprite sheet", async t => {
|
||||||
const messages = await eventToMessage({
|
const messages = await eventToMessage({
|
||||||
type: "m.room.message",
|
type: "m.room.message",
|
||||||
|
|
|
@ -15,7 +15,7 @@ This readme has the most important info. The rest is [in the docs folder.](https
|
||||||
* Modern: Supports new Discord features like replies, threads and stickers, and new Matrix features like edits, spaces and space membership.
|
* Modern: Supports new Discord features like replies, threads and stickers, and new Matrix features like edits, spaces and space membership.
|
||||||
* Efficient: Special attention has been given to memory usage, database indexes, disk footprint, runtime algorithms, and queries to the homeserver.
|
* Efficient: Special attention has been given to memory usage, database indexes, disk footprint, runtime algorithms, and queries to the homeserver.
|
||||||
* Reliable: Any errors on either side are notified on Matrix and can be retried.
|
* Reliable: Any errors on either side are notified on Matrix and can be retried.
|
||||||
* Tested: A test suite and code coverage make sure all the logic and special cases work.
|
* Tested: A test suite and code coverage make sure all the core logic works.
|
||||||
* Simple development: No build step (it's JavaScript, not TypeScript), minimal/lightweight dependencies, and abstraction only where necessary so that less background knowledge is required. No need to learn about Intents or library functions.
|
* Simple development: No build step (it's JavaScript, not TypeScript), minimal/lightweight dependencies, and abstraction only where necessary so that less background knowledge is required. No need to learn about Intents or library functions.
|
||||||
* No locking algorithm: Other bridges use a locking algorithm which is a source of frequent bugs. This bridge avoids the need for one.
|
* No locking algorithm: Other bridges use a locking algorithm which is a source of frequent bugs. This bridge avoids the need for one.
|
||||||
* Latest API: Being on the latest Discord API version lets it access all features, without the risk of deprecated API versions being removed.
|
* Latest API: Being on the latest Discord API version lets it access all features, without the risk of deprecated API versions being removed.
|
||||||
|
@ -42,14 +42,13 @@ Most features you'd expect in both directions, plus a little extra spice:
|
||||||
* Custom emojis in messages
|
* Custom emojis in messages
|
||||||
* Custom room names/avatars can be applied on Matrix-side
|
* Custom room names/avatars can be applied on Matrix-side
|
||||||
* Larger files from Discord are linked instead of reuploaded to Matrix
|
* Larger files from Discord are linked instead of reuploaded to Matrix
|
||||||
* Simulated user accounts are named @the_persons_username rather than @112233445566778899
|
|
||||||
|
|
||||||
For more information about features, [see the user guide.](https://gitdab.com/cadence/out-of-your-element/src/branch/main/docs/user-guide.md)
|
For more information about features, [see the user guide.](https://gitdab.com/cadence/out-of-your-element/src/branch/main/docs/user-guide.md)
|
||||||
|
|
||||||
## Caveats
|
## Caveats
|
||||||
|
|
||||||
* This bridge is not designed for puppetting.
|
* This bridge is not designed for puppetting.
|
||||||
* Direct Messaging is not supported until I figure out a good way of doing it.
|
* Direct Messaging is not supported yet.
|
||||||
|
|
||||||
## Efficiency details
|
## Efficiency details
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue