Compare commits
6 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 019f3f2ffb | |||
|
87fcdb18ab |
|||
|
015bedab69 |
|||
|
e25f788738 |
|||
|
cfa319eaa3 |
|||
|
714e990bef |
17 changed files with 46 additions and 696 deletions
48
package-lock.json
generated
48
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "out-of-your-element",
|
||||
"version": "3.5.1",
|
||||
"version": "3.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "out-of-your-element",
|
||||
"version": "3.5.1",
|
||||
"version": "3.4.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@chriscdn/promise-semaphore": "^3.0.1",
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
"enquirer": "^2.4.1",
|
||||
"entities": "^5.0.0",
|
||||
"get-relative-path": "^1.0.2",
|
||||
"h3": "^1.15.10",
|
||||
"h3": "^1.15.1",
|
||||
"heatsync": "^2.7.2",
|
||||
"htmx.org": "^2.0.4",
|
||||
"lru-cache": "^11.0.2",
|
||||
|
|
@ -276,9 +276,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
|
||||
"integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz",
|
||||
"integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
|
|
@ -1163,9 +1163,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -1488,9 +1488,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/domino": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/domino/-/domino-2.1.7.tgz",
|
||||
"integrity": "sha512-3rcXhx0ixJV2nj8J0tljzejTF73A35LVVdnTQu79UAqTBFEgYPMgGtykMuu/BDqaOZphATku1ddRUn/RtqUHYQ==",
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz",
|
||||
"integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
|
|
@ -1587,9 +1587,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz",
|
||||
"integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
|
|
@ -1617,9 +1617,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fullstore": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fullstore/-/fullstore-4.0.2.tgz",
|
||||
"integrity": "sha512-syOev4kA0lZy4VkfBJZ99ZL4cIiSgiKt0G8SpP0kla1tpM1c+V/jBOVY/OqqGtR2XLVcM83SjFPFC3R2YIwqjQ==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fullstore/-/fullstore-4.0.0.tgz",
|
||||
"integrity": "sha512-Y9hN79Q1CFU8akjGnTZoBnTzlA/o8wmtBijJOI8dKCmdC7GLX7OekpLxmbaeRetTOi4OdFGjfsg4c5dxP3jgPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
|
@ -1688,9 +1688,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/h3": {
|
||||
"version": "1.15.10",
|
||||
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.10.tgz",
|
||||
"integrity": "sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg==",
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.6.tgz",
|
||||
"integrity": "sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie-es": "^1.2.2",
|
||||
|
|
@ -1937,9 +1937,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-with-bigint": {
|
||||
"version": "3.5.8",
|
||||
"resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.8.tgz",
|
||||
"integrity": "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==",
|
||||
"version": "3.5.7",
|
||||
"resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.7.tgz",
|
||||
"integrity": "sha512-7ei3MdAI5+fJPVnKlW77TKNKwQ5ppSzWvhPuSuINT/GYW9ZOC1eRKOuhV9yHG5aEsUPj9BBx5JIekkmoLHxZOw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "out-of-your-element",
|
||||
"version": "3.5.1",
|
||||
"version": "3.4.0",
|
||||
"description": "A bridge between Matrix and Discord",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
"enquirer": "^2.4.1",
|
||||
"entities": "^5.0.0",
|
||||
"get-relative-path": "^1.0.2",
|
||||
"h3": "^1.15.10",
|
||||
"h3": "^1.15.1",
|
||||
"heatsync": "^2.7.2",
|
||||
"htmx.org": "^2.0.4",
|
||||
"lru-cache": "^11.0.2",
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ const {prompt} = require("enquirer")
|
|||
|
||||
reg.ooye.web_password = passwordResponse.web_password
|
||||
writeRegistration(reg)
|
||||
console.log("Saved. This change should be applied instantly.")
|
||||
console.log("Saved. Restart Out Of Your Element to apply this change.")
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -193,16 +193,6 @@ async function channelToKState(channel, guild, di) {
|
|||
// Don't overwrite room topic if the topic has been customised
|
||||
if (hasCustomTopic) delete channelKState["m.room.topic/"]
|
||||
|
||||
// Make voice channels be a Matrix voice room (MSC3417)
|
||||
if (channel.type === DiscordTypes.ChannelType.GuildVoice) {
|
||||
creationContent.type = "org.matrix.msc3417.call"
|
||||
channelKState["org.matrix.msc3401.call/"] = {
|
||||
"m.intent": "m.room",
|
||||
"m.type": "m.voice",
|
||||
"m.name": customName || channel.name
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add a space parent if it's self service
|
||||
// (The person setting up self-service has already put it in their preferred space to be able to get this far.)
|
||||
const autocreate = select("guild_active", "autocreate", {guild_id: guild.id}).pluck().get()
|
||||
|
|
|
|||
|
|
@ -190,17 +190,6 @@ test("channel2room: read-only discord channel", async t => {
|
|||
t.equal(api.getCalled(), 2)
|
||||
})
|
||||
|
||||
test("channel2room: voice channel", async t => {
|
||||
const api = mockAPI(t)
|
||||
const state = kstateStripConditionals(await channelToKState(testData.channel.voice, testData.guild.general, {api}).then(x => x.channelKState))
|
||||
t.equal(state["m.room.create/"].type, "org.matrix.msc3417.call")
|
||||
t.deepEqual(state["org.matrix.msc3401.call/"], {
|
||||
"m.intent": "m.room",
|
||||
"m.name": "🍞丨[8user] Piece",
|
||||
"m.type": "m.voice"
|
||||
})
|
||||
})
|
||||
|
||||
test("convertNameAndTopic: custom name and topic", t => {
|
||||
t.deepEqual(
|
||||
_convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, "hauntings"),
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ async function emojisToState(emojis, guild) {
|
|||
if (e.data?.errcode === "M_TOO_LARGE") { // Very unlikely to happen. Only possible for 3x-series emojis uploaded shortly after animated emojis were introduced, when there was no 256 KB size limit.
|
||||
return
|
||||
}
|
||||
e["emoji"] = {
|
||||
name: emoji.name,
|
||||
id: emoji.id
|
||||
}
|
||||
console.error(`Trying to handle emoji ${emoji.name} (${emoji.id}), but...`)
|
||||
throw e
|
||||
})
|
||||
))
|
||||
|
|
|
|||
|
|
@ -357,17 +357,6 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
}]
|
||||
}
|
||||
|
||||
if (message.type === DiscordTypes.MessageType.ChannelFollowAdd) {
|
||||
return [{
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.emote",
|
||||
body: `set this room to receive announcements from ${message.content}`,
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: tag`set this room to receive announcements from <strong>${message.content}</strong>`,
|
||||
"m.mentions": {}
|
||||
}]
|
||||
}
|
||||
|
||||
let isInteraction = (message.type === DiscordTypes.MessageType.ChatInputCommand || message.type === DiscordTypes.MessageType.ContextMenuCommand) && message.interaction && "name" in message.interaction
|
||||
let isThinkingInteraction = isInteraction && !!((message.flags || 0) & DiscordTypes.MessageFlags.Loading)
|
||||
|
||||
|
|
@ -669,7 +658,7 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
const match = repliedToEventSenderMxid.match(/^@([^:]*)/)
|
||||
assert(match)
|
||||
repliedToDisplayName = referenced.author.username || match[1] || "a Matrix user" // grab the localpart as the display name, whatever
|
||||
repliedToUserHtml = tag`<a href="https://matrix.to/#/${repliedToEventSenderMxid}">${repliedToDisplayName}</a>`
|
||||
repliedToUserHtml = `<a href="https://matrix.to/#/${repliedToEventSenderMxid}">${repliedToDisplayName}</a>`
|
||||
} else {
|
||||
repliedToDisplayName = referenced.author.global_name || referenced.author.username || "a Discord user"
|
||||
repliedToUserHtml = repliedToDisplayName
|
||||
|
|
@ -694,12 +683,6 @@ async function messageToEvent(message, guild, options = {}, di) {
|
|||
+ html
|
||||
body = `${repliedToDisplayName}: ${repliedToBody}`.split("\n").map(line => "> " + line).join("\n") // scenario 1 part B for mentions
|
||||
+ "\n\n" + body
|
||||
} else if (referenced.type === DiscordTypes.MessageType.UserJoin) {
|
||||
// Discord user join messages are bridged as joins, not text events. Generate substitute text for reply.
|
||||
const joinerMxid = select("sim", "mxid", {user_id: referenced.author.id}).pluck().get()
|
||||
const joinerHtml = joinerMxid ? tag`<a href="https://matrix.to/#/${joinerMxid}">${repliedToDisplayName}</a>` : tag`<strong>${repliedToDisplayName}</strong>`
|
||||
html = `<blockquote>${joinerHtml} joined the room</blockquote>` + html
|
||||
body = `> ${repliedToDisplayName} joined the room\n\n` + body
|
||||
} else { // repliedToUnknownEvent
|
||||
const dateDisplay = dUtils.howOldUnbridgedMessage(referenced.timestamp, message.timestamp)
|
||||
html = `<blockquote>In reply to ${dateDisplay} from ${repliedToDisplayName}:`
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ const {MatrixServerError} = require("../../matrix/mreq")
|
|||
const data = require("../../../test/data")
|
||||
const {mockGetEffectivePower} = require("../../matrix/utils.test")
|
||||
const Ty = require("../../types")
|
||||
const {db} = require("../../passthrough")
|
||||
|
||||
/**
|
||||
* @param {string} roomID
|
||||
|
|
@ -734,31 +733,6 @@ test("message2event: reply to a Discord message that wasn't bridged", async t =>
|
|||
}])
|
||||
})
|
||||
|
||||
test("message2event: reply to a Discord member join (who didn't join on Matrix)", async t => {
|
||||
const events = await messageToEvent(data.message.reply_to_member_join, data.guild.general)
|
||||
t.deepEqual(events, [{
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.text",
|
||||
body: "> PEASANT!! joined the room\n\nwhen the broke friend who we pay to bring food shows up at the medieval lord party",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "<blockquote><strong>PEASANT!!</strong> joined the room</blockquote>when the broke friend who we pay to bring food shows up at the medieval lord party",
|
||||
"m.mentions": {}
|
||||
}])
|
||||
})
|
||||
|
||||
test("message2event: reply to a Discord member join (who did join on Matrix)", async t => {
|
||||
db.prepare("INSERT INTO sim (user_id, username, sim_name, mxid) VALUES ('1461677775554478161', 'peasant321_76775', 'peasant321_76775', '@_ooye_peasant321_76775:cadence.moe')").run()
|
||||
const events = await messageToEvent(data.message.reply_to_member_join, data.guild.general)
|
||||
t.deepEqual(events, [{
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.text",
|
||||
body: "> PEASANT!! joined the room\n\nwhen the broke friend who we pay to bring food shows up at the medieval lord party",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: `<blockquote><a href="https://matrix.to/#/@_ooye_peasant321_76775:cadence.moe">PEASANT!!</a> joined the room</blockquote>when the broke friend who we pay to bring food shows up at the medieval lord party`,
|
||||
"m.mentions": {}
|
||||
}])
|
||||
})
|
||||
|
||||
test("message2event: simple written @mention for matrix user", async t => {
|
||||
const events = await messageToEvent(data.message.simple_written_at_mention_for_matrix, data.guild.general, {}, {
|
||||
api: {
|
||||
|
|
@ -1168,19 +1142,6 @@ test("message2event: type 4 channel name change", async t => {
|
|||
}])
|
||||
})
|
||||
|
||||
test("message2event: type 12 channel follow add", async t => {
|
||||
const events = await messageToEvent(data.special_message.channel_follow_add, data.guild.general)
|
||||
t.deepEqual(events, [{
|
||||
$type: "m.room.message",
|
||||
"m.mentions": {},
|
||||
msgtype: "m.emote",
|
||||
body: "set this room to receive announcements from PluralKit #downtime",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "set this room to receive announcements from <strong>PluralKit #downtime</strong>",
|
||||
"m.mentions": {}
|
||||
}])
|
||||
})
|
||||
|
||||
test("message2event: thread start message reference", async t => {
|
||||
const events = await messageToEvent(data.special_message.thread_start_context, data.guild.general, {}, {
|
||||
api: {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ function pinsToList(pins, kstate) {
|
|||
/** @type {string[]} */
|
||||
const result = []
|
||||
for (const pin of pins.items) {
|
||||
const eventID = select("event_message", "event_id", {message_id: pin.message.id}, "ORDER BY part ASC").pluck().get()
|
||||
const eventID = select("event_message", "event_id", {message_id: pin.message.id, part: 0}).pluck().get()
|
||||
if (eventID && !alreadyPinned.includes(eventID)) result.push(eventID)
|
||||
}
|
||||
result.reverse()
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ async function _interact({guild_id, data}, {api}) {
|
|||
// from Matrix
|
||||
const event = await api.getEvent(message.room_id, message.event_id)
|
||||
const via = await utils.getViaServersQuery(message.room_id, api)
|
||||
|
||||
const channelsInGuild = discord.guildChannelMap.get(guild_id)
|
||||
assert(channelsInGuild)
|
||||
const inChannels = channelsInGuild
|
||||
|
|
@ -62,11 +61,6 @@ async function _interact({guild_id, data}, {api}) {
|
|||
.map(/** @returns {DiscordTypes.APIGuildChannel} */ cid => discord.channels.get(cid))
|
||||
.sort((a, b) => webGuild._getPosition(a, discord.channels) - webGuild._getPosition(b, discord.channels))
|
||||
.filter(channel => from("channel_room").join("member_cache", "room_id").select("mxid").where({channel_id: channel.id, mxid: event.sender}).get())
|
||||
let inChannelsText = inChannels.map(c => `<#${c.id}>`).join(" • ")
|
||||
if (inChannelsText.length > 1024) {
|
||||
inChannelsText = `In ${inChannels.length} channels`
|
||||
}
|
||||
|
||||
const matrixMember = select("member_cache", ["displayname", "avatar_url"], {room_id: message.room_id, mxid: event.sender}).get()
|
||||
let name = matrixMember?.displayname || event.sender
|
||||
let avatar = utils.getPublicUrlForMxc(matrixMember?.avatar_url)
|
||||
|
|
@ -104,7 +98,7 @@ async function _interact({guild_id, data}, {api}) {
|
|||
color: 0x0dbd8b,
|
||||
fields: [{
|
||||
name: "In Channels",
|
||||
value: inChannelsText
|
||||
value: inChannels.map(c => `<#${c.id}>`).join(" • ")
|
||||
}, {
|
||||
name: "\u200b",
|
||||
value: idInfo
|
||||
|
|
|
|||
|
|
@ -182,394 +182,6 @@ function filterTo(xs, fn) {
|
|||
return filtered
|
||||
}
|
||||
|
||||
const supportedPlaintextPreviewExtensions = new Set([
|
||||
"4d",
|
||||
"abnf",
|
||||
"accesslog",
|
||||
"actionscript",
|
||||
"ada",
|
||||
"adoc",
|
||||
"alan",
|
||||
"angelscript",
|
||||
"ansi",
|
||||
"apache",
|
||||
"apacheconf",
|
||||
"applescript",
|
||||
"arcade",
|
||||
"arduino",
|
||||
"arm",
|
||||
"armasm",
|
||||
"as",
|
||||
"asc",
|
||||
"asciidoc",
|
||||
"aspectj",
|
||||
"ass",
|
||||
"atom",
|
||||
"autohotkey",
|
||||
"autoit",
|
||||
"avrasm",
|
||||
"awk",
|
||||
"axapta",
|
||||
"bash",
|
||||
"basic",
|
||||
"bat",
|
||||
"bbcode",
|
||||
"bf",
|
||||
"bind",
|
||||
"blade",
|
||||
"bnf",
|
||||
"brainfuck",
|
||||
"c",
|
||||
"c++",
|
||||
"cal",
|
||||
"capnp",
|
||||
"capnproto",
|
||||
"cc",
|
||||
"chaos",
|
||||
"chapel",
|
||||
"chpl",
|
||||
"cisco",
|
||||
"clj",
|
||||
"clojure",
|
||||
"cls",
|
||||
"cmake.in",
|
||||
"cmake",
|
||||
"cmd",
|
||||
"coffee",
|
||||
"coffeescript",
|
||||
"console",
|
||||
"coq",
|
||||
"cos",
|
||||
"cpc",
|
||||
"cpp",
|
||||
"cr",
|
||||
"craftcms",
|
||||
"crm",
|
||||
"crmsh",
|
||||
"crystal",
|
||||
"cs",
|
||||
"csharp",
|
||||
"cshtml",
|
||||
"cson",
|
||||
"csp",
|
||||
"css",
|
||||
"csv",
|
||||
"cxx",
|
||||
"cypher",
|
||||
"d",
|
||||
"dart",
|
||||
"delphi",
|
||||
"dfm",
|
||||
"diff",
|
||||
"django",
|
||||
"dns",
|
||||
"docker",
|
||||
"dockerfile",
|
||||
"dos",
|
||||
"dpr",
|
||||
"dsconfig",
|
||||
"dst",
|
||||
"dts",
|
||||
"dust",
|
||||
"dylan",
|
||||
"ebnf",
|
||||
"elixir",
|
||||
"elm",
|
||||
"erl",
|
||||
"erlang",
|
||||
"ex",
|
||||
"extempore",
|
||||
"f90",
|
||||
"f95",
|
||||
"fix",
|
||||
"fortran",
|
||||
"freepascal",
|
||||
"fs",
|
||||
"fsharp",
|
||||
"gams",
|
||||
"gauss",
|
||||
"gawk",
|
||||
"gcode",
|
||||
"gdscript",
|
||||
"gemspec",
|
||||
"gf",
|
||||
"gherkin",
|
||||
"glsl",
|
||||
"gms",
|
||||
"gn",
|
||||
"gni",
|
||||
"go",
|
||||
"godot",
|
||||
"golang",
|
||||
"golo",
|
||||
"gololang",
|
||||
"gradle",
|
||||
"graph",
|
||||
"groovy",
|
||||
"gss",
|
||||
"gyp",
|
||||
"h",
|
||||
"h++",
|
||||
"haml",
|
||||
"handlebars",
|
||||
"haskell",
|
||||
"haxe",
|
||||
"hbs",
|
||||
"hcl",
|
||||
"hh",
|
||||
"hpp",
|
||||
"hs",
|
||||
"html.handlebars",
|
||||
"html.hbs",
|
||||
"html",
|
||||
"http",
|
||||
"https",
|
||||
"hx",
|
||||
"hxx",
|
||||
"hy",
|
||||
"hylang",
|
||||
"i",
|
||||
"i7",
|
||||
"iced",
|
||||
"iecst",
|
||||
"inform7",
|
||||
"ini",
|
||||
"ino",
|
||||
"instances",
|
||||
"iol",
|
||||
"irb",
|
||||
"irpf90",
|
||||
"java",
|
||||
"javascript",
|
||||
"jinja",
|
||||
"jolie",
|
||||
"js",
|
||||
"json",
|
||||
"jsp",
|
||||
"jsx",
|
||||
"julia-repl",
|
||||
"julia",
|
||||
"k",
|
||||
"kaos",
|
||||
"kdb",
|
||||
"kotlin",
|
||||
"kt",
|
||||
"lasso",
|
||||
"lassoscript",
|
||||
"lazarus",
|
||||
"ldif",
|
||||
"leaf",
|
||||
"lean",
|
||||
"less",
|
||||
"lfm",
|
||||
"lisp",
|
||||
"livecodeserver",
|
||||
"livescript",
|
||||
"ln",
|
||||
"lock",
|
||||
"log",
|
||||
"lpr",
|
||||
"ls",
|
||||
"ls",
|
||||
"lua",
|
||||
"mak",
|
||||
"make",
|
||||
"makefile",
|
||||
"markdown",
|
||||
"mathematica",
|
||||
"matlab",
|
||||
"mawk",
|
||||
"maxima",
|
||||
"md",
|
||||
"mel",
|
||||
"mercury",
|
||||
"mirc",
|
||||
"mizar",
|
||||
"mk",
|
||||
"mkd",
|
||||
"mkdown",
|
||||
"ml",
|
||||
"ml",
|
||||
"mm",
|
||||
"mma",
|
||||
"mojolicious",
|
||||
"monkey",
|
||||
"moon",
|
||||
"moonscript",
|
||||
"mrc",
|
||||
"n1ql",
|
||||
"nawk",
|
||||
"nc",
|
||||
"never",
|
||||
"nginx",
|
||||
"nginxconf",
|
||||
"nim",
|
||||
"nimrod",
|
||||
"nix",
|
||||
"nsis",
|
||||
"obj-c",
|
||||
"obj-c++",
|
||||
"objc",
|
||||
"objective-c++",
|
||||
"objectivec",
|
||||
"ocaml",
|
||||
"ocl",
|
||||
"ol",
|
||||
"openscad",
|
||||
"osascript",
|
||||
"oxygene",
|
||||
"p21",
|
||||
"parser3",
|
||||
"pas",
|
||||
"pascal",
|
||||
"patch",
|
||||
"pcmk",
|
||||
"perl",
|
||||
"pf.conf",
|
||||
"pf",
|
||||
"pgsql",
|
||||
"php",
|
||||
"php3",
|
||||
"php4",
|
||||
"php5",
|
||||
"php6",
|
||||
"php7",
|
||||
"pl",
|
||||
"plaintext",
|
||||
"plist",
|
||||
"pm",
|
||||
"podspec",
|
||||
"pony",
|
||||
"postgres",
|
||||
"postgresql",
|
||||
"powershell",
|
||||
"pp",
|
||||
"processing",
|
||||
"profile",
|
||||
"prolog",
|
||||
"properties",
|
||||
"proto",
|
||||
"protobuf",
|
||||
"ps",
|
||||
"ps1",
|
||||
"puppet",
|
||||
"py",
|
||||
"pycon",
|
||||
"python-repl",
|
||||
"python",
|
||||
"qml",
|
||||
"r",
|
||||
"razor-cshtml",
|
||||
"razor",
|
||||
"rb",
|
||||
"re",
|
||||
"reasonml",
|
||||
"rebol",
|
||||
"red-system",
|
||||
"red",
|
||||
"redbol",
|
||||
"rf",
|
||||
"rib",
|
||||
"robot",
|
||||
"rpm-spec",
|
||||
"rpm-specfile",
|
||||
"rpm",
|
||||
"rs",
|
||||
"rsl",
|
||||
"rss",
|
||||
"ruby",
|
||||
"ruleslanguage",
|
||||
"rust",
|
||||
"sas",
|
||||
"SAS",
|
||||
"sc",
|
||||
"scad",
|
||||
"scala",
|
||||
"scheme",
|
||||
"sci",
|
||||
"scilab",
|
||||
"scl",
|
||||
"scss",
|
||||
"sh",
|
||||
"shell",
|
||||
"shexc",
|
||||
"smali",
|
||||
"smalltalk",
|
||||
"sml",
|
||||
"sol",
|
||||
"solidity",
|
||||
"spec",
|
||||
"specfile",
|
||||
"sql",
|
||||
"srt",
|
||||
"ssa",
|
||||
"st",
|
||||
"stan",
|
||||
"stanfuncs",
|
||||
"stata",
|
||||
"step",
|
||||
"stp",
|
||||
"structured-text",
|
||||
"styl",
|
||||
"stylus",
|
||||
"subunit",
|
||||
"supercollider",
|
||||
"svelte",
|
||||
"svg",
|
||||
"swift",
|
||||
"tao",
|
||||
"tap",
|
||||
"tcl",
|
||||
"terraform",
|
||||
"tex",
|
||||
"text",
|
||||
"tf",
|
||||
"thor",
|
||||
"thrift",
|
||||
"tk",
|
||||
"toml",
|
||||
"tp",
|
||||
"ts",
|
||||
"tsql",
|
||||
"tsx",
|
||||
"ttml",
|
||||
"twig",
|
||||
"txt",
|
||||
"typescript",
|
||||
"unicorn-rails-log",
|
||||
"v",
|
||||
"vala",
|
||||
"vb",
|
||||
"vba",
|
||||
"vbnet",
|
||||
"vbs",
|
||||
"vbscript",
|
||||
"verilog",
|
||||
"vhdl",
|
||||
"vim",
|
||||
"vtt",
|
||||
"wl",
|
||||
"x++",
|
||||
"x86asm",
|
||||
"xhtml",
|
||||
"xjb",
|
||||
"xl",
|
||||
"xml",
|
||||
"xpath",
|
||||
"xq",
|
||||
"xquery",
|
||||
"xsd",
|
||||
"xsl",
|
||||
"xtlang",
|
||||
"xtm",
|
||||
"yaml",
|
||||
"yml",
|
||||
"zep",
|
||||
"zephir",
|
||||
"zone",
|
||||
"zsh"
|
||||
])
|
||||
|
||||
module.exports.getPermissions = getPermissions
|
||||
module.exports.getDefaultPermissions = getDefaultPermissions
|
||||
module.exports.hasPermission = hasPermission
|
||||
|
|
@ -582,4 +194,3 @@ module.exports.timestampToSnowflakeInexact = timestampToSnowflakeInexact
|
|||
module.exports.getPublicUrlForCdn = getPublicUrlForCdn
|
||||
module.exports.howOldUnbridgedMessage = howOldUnbridgedMessage
|
||||
module.exports.filterTo = filterTo
|
||||
module.exports.supportedPlaintextPreviewExtensions = supportedPlaintextPreviewExtensions
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ async function updatePins(pins, prev) {
|
|||
const diff = diffPins.diffPins(pins, prev)
|
||||
for (const [event_id, added] of diff) {
|
||||
const row = from("event_message").join("message_room", "message_id").join("historical_channel_room", "historical_room_index")
|
||||
.select("reference_channel_id", "message_id").where({event_id}).and("ORDER BY part ASC").get()
|
||||
.select("reference_channel_id", "message_id").get()
|
||||
if (!row) continue
|
||||
if (added) {
|
||||
discord.snow.channel.addChannelPinnedMessage(row.reference_channel_id, row.message_id, "Message pinned on Matrix")
|
||||
|
|
|
|||
|
|
@ -816,6 +816,16 @@ async function eventToMessage(event, guild, channel, di) {
|
|||
if (shouldProcessTextEvent) {
|
||||
if (event.content.format === "org.matrix.custom.html" && event.content.formatted_body) {
|
||||
let input = event.content.formatted_body
|
||||
if (perMessageProfile?.has_fallback) {
|
||||
// Strip fallback elements added for clients that don't support per-message profiles.
|
||||
// Deviates from recommended regexp in MSC to be less strict. Avoiding an HTML parser for performance reasons.
|
||||
// ┌────A────┐ Opening HTML tag: capture tag name and stay within tag
|
||||
// ┆ ┆┌─────────────B────────────┐ This text in the tag somewhere, presumably an attribute name
|
||||
// ┆ ┆┆ ┆┌─C──┐ Rest of the opening tag
|
||||
// ┆ ┆┆ ┆┆ ┆┌─D─┐ Tag content (no more tags allowed within)
|
||||
// ┆ ┆┆ ┆┆ ┆┆ ┆┌─E──┐ Closing tag matching opening tag name
|
||||
input = input.replace(/<(\w+)[^>]*\bdata-mx-profile-fallback\b[^>]*>[^<]*<\/\1>/g, "")
|
||||
}
|
||||
if (event.content.msgtype === "m.emote") {
|
||||
input = `* ${displayName} ${input}`
|
||||
}
|
||||
|
|
@ -876,9 +886,8 @@ async function eventToMessage(event, guild, channel, di) {
|
|||
const doc = domino.createDocument(
|
||||
// DOM parsers arrange elements in the <head> and <body>. Wrapping in a custom element ensures elements are reliably arranged in a single element.
|
||||
'<x-turndown id="turndown-root">' + input + '</x-turndown>'
|
||||
)
|
||||
const root = doc.getElementById("turndown-root")
|
||||
assert(root)
|
||||
);
|
||||
const root = doc.getElementById("turndown-root");
|
||||
async function forEachNode(event, node) {
|
||||
for (; node; node = node.nextSibling) {
|
||||
// Check written mentions
|
||||
|
|
@ -894,8 +903,7 @@ async function eventToMessage(event, guild, channel, di) {
|
|||
let preNode
|
||||
if (node.nodeType === 3 && node.nodeValue.includes("```") && (preNode = nodeIsChildOf(node, ["PRE"]))) {
|
||||
if (preNode.firstChild?.nodeName === "CODE") {
|
||||
let ext = preNode.firstChild.className.match(/language-(\S+)/)?.[1]
|
||||
if (!dUtils.supportedPlaintextPreviewExtensions.has(ext)) ext = "txt"
|
||||
const ext = preNode.firstChild.className.match(/language-(\S+)/)?.[1] || "txt"
|
||||
const filename = `inline_code.${ext}`
|
||||
// Build the replacement <code> node
|
||||
const replacementCode = doc.createElement("code")
|
||||
|
|
@ -932,7 +940,6 @@ async function eventToMessage(event, guild, channel, di) {
|
|||
}
|
||||
}
|
||||
await forEachNode(event, root)
|
||||
if (perMessageProfile?.has_fallback) root.querySelectorAll("[data-mx-profile-fallback]").forEach(x => x.remove())
|
||||
|
||||
// SPRITE SHEET EMOJIS FEATURE: Emojis at the end of the message that we don't know about will be reuploaded as a sprite sheet.
|
||||
// First we need to determine which emojis are at the end.
|
||||
|
|
|
|||
|
|
@ -1155,38 +1155,6 @@ test("event2message: code blocks are uploaded as attachments instead if they con
|
|||
)
|
||||
})
|
||||
|
||||
test("event2message: code blocks are uploaded as attachments instead if they contain incompatible backticks (use txt extension if discord does not recognise the language)", async t => {
|
||||
t.deepEqual(
|
||||
await eventToMessage({
|
||||
type: "m.room.message",
|
||||
sender: "@cadence:cadence.moe",
|
||||
content: {
|
||||
msgtype: "m.text",
|
||||
body: "wrong body",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: 'So if you run code like this<pre><code class="language-if">System.out.println("```");</code></pre>it should print a markdown formatted code block'
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
messagesToDelete: [],
|
||||
messagesToEdit: [],
|
||||
messagesToSend: [{
|
||||
username: "cadence [they]",
|
||||
content: "So if you run code like this `[inline_code.txt]` it should print a markdown formatted code block",
|
||||
attachments: [{id: "0", filename: "inline_code.txt"}],
|
||||
pendingFiles: [{name: "inline_code.txt", buffer: Buffer.from('System.out.println("```");')}],
|
||||
avatar_url: undefined,
|
||||
allowed_mentions: {
|
||||
parse: ["users", "roles"]
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test("event2message: code blocks are uploaded as attachments instead if they contain incompatible backticks (default to txt file extension)", async t => {
|
||||
t.deepEqual(
|
||||
await eventToMessage({
|
||||
|
|
|
|||
|
|
@ -78,15 +78,6 @@ function readRegistration() {
|
|||
/** @type {import("../types").AppServiceRegistrationConfig} */ // @ts-ignore
|
||||
let reg = readRegistration()
|
||||
|
||||
if (reg) {
|
||||
fs.watch(registrationFilePath, {persistent: false}, () => {
|
||||
let newReg = readRegistration()
|
||||
if (newReg) {
|
||||
Object.assign(reg, newReg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.registrationFilePath = registrationFilePath
|
||||
module.exports.readRegistration = readRegistration
|
||||
module.exports.getTemplateRegistration = getTemplateRegistration
|
||||
|
|
|
|||
16
src/stdin.js
16
src/stdin.js
|
|
@ -23,22 +23,6 @@ const setPresence = sync.require("./d2m/actions/set-presence")
|
|||
const channelWebhook = sync.require("./m2d/actions/channel-webhook")
|
||||
const guildID = "112760669178241024"
|
||||
|
||||
async function ping() {
|
||||
const result = await api.ping().catch(e => ({ok: false, status: "net", root: e.message}))
|
||||
if (result.ok) {
|
||||
return "Ping OK. The homeserver and OOYE are talking to each other fine."
|
||||
} else {
|
||||
if (typeof result.root === "string") {
|
||||
var msg = `Cannot reach homeserver: ${result.root}`
|
||||
} else if (result.root.error) {
|
||||
var msg = `Homeserver said: [${result.status}] ${result.root.error}`
|
||||
} else {
|
||||
var msg = `Homeserver said: [${result.status}] ${JSON.stringify(result.root)}`
|
||||
}
|
||||
return msg + "\nMatrix->Discord won't work until you fix this.\nIf your installation has recently changed, consider `npm run setup` again."
|
||||
}
|
||||
}
|
||||
|
||||
if (process.stdin.isTTY) {
|
||||
setImmediate(() => {
|
||||
if (!passthrough.repl) {
|
||||
|
|
|
|||
125
test/data.js
125
test/data.js
|
|
@ -19,26 +19,6 @@ module.exports = {
|
|||
default_thread_rate_limit_per_user: 0,
|
||||
guild_id: "112760669178241024"
|
||||
},
|
||||
voice: {
|
||||
voice_background_display: null,
|
||||
version: 1774469910848,
|
||||
user_limit: 0,
|
||||
type: 2,
|
||||
theme_color: null,
|
||||
status: null,
|
||||
rtc_region: null,
|
||||
rate_limit_per_user: 0,
|
||||
position: 0,
|
||||
permission_overwrites: [],
|
||||
parent_id: "805261291908104252",
|
||||
nsfw: false,
|
||||
name: "🍞丨[8user] Piece",
|
||||
last_message_id: "1459912691098325137",
|
||||
id: "1036840786093953084",
|
||||
flags: 0,
|
||||
bitrate: 256000,
|
||||
guild_id: "112760669178241024"
|
||||
},
|
||||
updates: {
|
||||
type: 0,
|
||||
topic: "Updates and release announcements for Out Of Your Element.",
|
||||
|
|
@ -2035,80 +2015,6 @@ module.exports = {
|
|||
tts: false
|
||||
}
|
||||
},
|
||||
reply_to_member_join: {
|
||||
type: 19,
|
||||
content: "when the broke friend who we pay to bring food shows up at the medieval lord party",
|
||||
mentions: [],
|
||||
mention_roles: [],
|
||||
attachments: [],
|
||||
embeds: [],
|
||||
timestamp: "2026-03-30T12:11:04.443000+00:00",
|
||||
edited_timestamp: null,
|
||||
flags: 0,
|
||||
components: [],
|
||||
id: "1488148556962332692",
|
||||
channel_id: "475599038536744962",
|
||||
author: {
|
||||
id: "576945009408999426",
|
||||
username: "randomllama121",
|
||||
avatar: "08510a70f957106dad1580323c40cd7a",
|
||||
discriminator: "0",
|
||||
public_flags: 128,
|
||||
flags: 128,
|
||||
banner: null,
|
||||
accent_color: null,
|
||||
global_name: "random :3",
|
||||
avatar_decoration_data: null,
|
||||
collectibles: null,
|
||||
display_name_styles: null,
|
||||
banner_color: null,
|
||||
clan: null,
|
||||
primary_guild: null
|
||||
},
|
||||
pinned: false,
|
||||
mention_everyone: false,
|
||||
tts: false,
|
||||
message_reference: {
|
||||
type: 0,
|
||||
channel_id: "475599038536744962",
|
||||
message_id: "1488146734352826478",
|
||||
guild_id: "475599038536744960"
|
||||
},
|
||||
referenced_message: {
|
||||
type: 7,
|
||||
content: "",
|
||||
mentions: [],
|
||||
mention_roles: [],
|
||||
attachments: [],
|
||||
embeds: [],
|
||||
timestamp: "2026-03-30T12:03:49.899000+00:00",
|
||||
edited_timestamp: null,
|
||||
flags: 0,
|
||||
components: [],
|
||||
id: "1488146734352826478",
|
||||
channel_id: "475599038536744962",
|
||||
author: {
|
||||
id: "1461677775554478161",
|
||||
username: "peasant321_76775",
|
||||
avatar: null,
|
||||
discriminator: "0",
|
||||
public_flags: 0,
|
||||
flags: 0,
|
||||
banner: null,
|
||||
accent_color: null,
|
||||
global_name: "PEASANT!!",
|
||||
avatar_decoration_data: null,
|
||||
collectibles: null,
|
||||
display_name_styles: null,
|
||||
banner_color: null,
|
||||
clan: null,
|
||||
primary_guild: null
|
||||
},
|
||||
pinned: false,
|
||||
mention_everyone: false,
|
||||
tts: false
|
||||
}
|
||||
},
|
||||
attachment_no_content: {
|
||||
id: "1124628646670389348",
|
||||
type: 0,
|
||||
|
|
@ -6264,37 +6170,6 @@ module.exports = {
|
|||
components: [],
|
||||
position: 12
|
||||
},
|
||||
channel_follow_add: {
|
||||
type: 12,
|
||||
content: "PluralKit #downtime",
|
||||
attachments: [],
|
||||
embeds: [],
|
||||
timestamp: "2026-03-24T23:16:04.097Z",
|
||||
edited_timestamp: null,
|
||||
flags: 0,
|
||||
components: [],
|
||||
id: "1486141581047369888",
|
||||
channel_id: "1451125453082591314",
|
||||
author: {
|
||||
id: "154058479798059009",
|
||||
username: "exaptations",
|
||||
discriminator: "0",
|
||||
avatar: "57b5cfe09a48a5902f2eb8fa65bb1b80",
|
||||
bot: false,
|
||||
flags: 0,
|
||||
globalName: "Exa",
|
||||
},
|
||||
pinned: false,
|
||||
mentions: [],
|
||||
mention_roles: [],
|
||||
mention_everyone: false,
|
||||
tts: false,
|
||||
message_reference: {
|
||||
type: 0,
|
||||
channel_id: "1015204661701124206",
|
||||
guild_id: "466707357099884544"
|
||||
}
|
||||
},
|
||||
updated_to_start_thread_from_here: {
|
||||
t: "MESSAGE_UPDATE",
|
||||
s: 19,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue