Compare commits
2 commits
542070b33b
...
6e85237cab
Author | SHA1 | Date | |
---|---|---|---|
6e85237cab | |||
73590257c8 |
6 changed files with 2451 additions and 1801 deletions
3690
pnpm-lock.yaml
3690
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
123
src/index.js
123
src/index.js
|
@ -1,15 +1,20 @@
|
||||||
const Dysnomia = require("@projectdysnomia/dysnomia");
|
const Dysnomia = require("@projectdysnomia/dysnomia");
|
||||||
const logger = require("./lib/logger.js");
|
const logger = require("./lib/logger.js");
|
||||||
const fs = require("fs");
|
const fs = require("node:fs");
|
||||||
const {resolve} = require("path");
|
const {resolve} = require("node:path");
|
||||||
const sqlite3 = require("sqlite3");
|
const sqlite3 = require("sqlite3");
|
||||||
const {instead, before} = require("spitroast");
|
const {instead, before} = require("spitroast");
|
||||||
|
|
||||||
const config = require("../config.json");
|
const config = require("../config.json");
|
||||||
const apikeys = require("../apikeys.json");
|
const apikeys = require("../apikeys.json");
|
||||||
const Command = require("./lib/command.js");
|
|
||||||
const events = require("./lib/events.js");
|
const events = require("./lib/events.js");
|
||||||
|
const {formatUsername} = require("./lib/utils.js");
|
||||||
const timer = require("./lib/timer.js");
|
const timer = require("./lib/timer.js");
|
||||||
|
const Command = require("./lib/command.js");
|
||||||
|
const CommandDispatcher = require("./lib/commandDispatcher.js");
|
||||||
|
const InteractionCommand = require("./lib/interactionCommand.js");
|
||||||
|
const {InteractionDispatcher} = require("./lib/interactionDispatcher.js");
|
||||||
|
|
||||||
const bot = new Dysnomia.Client(config.token, {
|
const bot = new Dysnomia.Client(config.token, {
|
||||||
defaultImageFormat: "png",
|
defaultImageFormat: "png",
|
||||||
|
@ -17,9 +22,11 @@ const bot = new Dysnomia.Client(config.token, {
|
||||||
gateway: {
|
gateway: {
|
||||||
intents: Object.values(Dysnomia.Constants.Intents),
|
intents: Object.values(Dysnomia.Constants.Intents),
|
||||||
},
|
},
|
||||||
|
restMode: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const commands = new Dysnomia.Collection();
|
const commands = new Dysnomia.Collection();
|
||||||
|
const interactionCommands = new Dysnomia.Collection();
|
||||||
|
|
||||||
const database = new sqlite3.Database(resolve(__dirname, "..", "database.db"));
|
const database = new sqlite3.Database(resolve(__dirname, "..", "database.db"));
|
||||||
|
|
||||||
|
@ -33,6 +40,9 @@ function registerCommand(cmdObj) {
|
||||||
aliases.length > 0 ? ` (aliases: ${aliases.join(", ")})` : ""
|
aliases.length > 0 ? ` (aliases: ${aliases.join(", ")})` : ""
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
|
} else if (cmdObj instanceof InteractionCommand) {
|
||||||
|
interactionCommands.set(cmdObj.name, cmdObj);
|
||||||
|
logger.info("hf:cmd", `Registered interaction command '${cmdObj.name}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,21 +51,20 @@ global.hf = {
|
||||||
config,
|
config,
|
||||||
apikeys,
|
apikeys,
|
||||||
commands,
|
commands,
|
||||||
|
interactionCommands,
|
||||||
registerCommand,
|
registerCommand,
|
||||||
events,
|
events,
|
||||||
timer,
|
timer,
|
||||||
database,
|
database,
|
||||||
};
|
};
|
||||||
|
|
||||||
const CommandDispatcher = require("./lib/commandDispatcher.js");
|
|
||||||
const {formatUsername} = require("./lib/utils.js");
|
|
||||||
|
|
||||||
for (const file of fs.readdirSync(resolve(__dirname, "modules"))) {
|
for (const file of fs.readdirSync(resolve(__dirname, "modules"))) {
|
||||||
require(resolve(__dirname, "modules", file));
|
require(resolve(__dirname, "modules", file));
|
||||||
logger.info("hf:modules", `Loaded module: '${file}'`);
|
logger.info("hf:modules", `Loaded module: '${file}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.on("messageCreate", async (msg) => {
|
bot.on("messageCreate", async (msg) => {
|
||||||
|
try {
|
||||||
// fix DMs cause of gateway v8 changes
|
// fix DMs cause of gateway v8 changes
|
||||||
if (
|
if (
|
||||||
!(msg.channel instanceof Dysnomia.Channel) &&
|
!(msg.channel instanceof Dysnomia.Channel) &&
|
||||||
|
@ -69,8 +78,17 @@ bot.on("messageCreate", async (msg) => {
|
||||||
if (!(msg.channel instanceof Dysnomia.Channel)) return;
|
if (!(msg.channel instanceof Dysnomia.Channel)) return;
|
||||||
|
|
||||||
await CommandDispatcher(msg);
|
await CommandDispatcher(msg);
|
||||||
|
} catch (err) {
|
||||||
|
const stack = (err?.stack ?? err.message).split("\n");
|
||||||
|
const error = stack.shift();
|
||||||
|
logger.error(
|
||||||
|
"hf:main",
|
||||||
|
`Failed to dispatch command: ${error}\n\t${stack.join("\n\t")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
bot.on("messageUpdate", (msg, oldMsg) => {
|
bot.on("messageUpdate", async (msg, oldMsg) => {
|
||||||
|
try {
|
||||||
const oneDay = Date.now() - 86400000;
|
const oneDay = Date.now() - 86400000;
|
||||||
if (
|
if (
|
||||||
msg.timestamp > oneDay &&
|
msg.timestamp > oneDay &&
|
||||||
|
@ -78,7 +96,75 @@ bot.on("messageUpdate", (msg, oldMsg) => {
|
||||||
oldMsg &&
|
oldMsg &&
|
||||||
oldMsg.content !== msg.content
|
oldMsg.content !== msg.content
|
||||||
) {
|
) {
|
||||||
CommandDispatcher(msg);
|
await CommandDispatcher(msg);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const stack = (err?.stack ?? err.message).split("\n");
|
||||||
|
const error = stack.shift();
|
||||||
|
logger.error(
|
||||||
|
"hf:main",
|
||||||
|
`Failed to dispatch command update: ${error}\n\t${stack.join("\n\t")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
bot.on("messageReactionAdd", async (msg, reaction, reactor) => {
|
||||||
|
if (msg.author.id !== bot.user.id) return;
|
||||||
|
if (reaction.name !== "\u274c") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let channel = msg.channel;
|
||||||
|
if (!(channel instanceof Dysnomia.Channel)) {
|
||||||
|
const newChannel = hf.bot.getChannel(channel.id);
|
||||||
|
if (newChannel) {
|
||||||
|
channel = newChannel;
|
||||||
|
} else {
|
||||||
|
channel = await hf.bot.getRESTChannel(channel.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msg.messageReference) {
|
||||||
|
msg = await channel.getMessage(msg.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msg.messageReference) return;
|
||||||
|
|
||||||
|
const ref = await channel.getMessage(msg.messageReference.messageID);
|
||||||
|
if (!ref) return;
|
||||||
|
if (ref.author.id !== reactor.id) return;
|
||||||
|
|
||||||
|
await msg.delete("Command sender requested output deletion.");
|
||||||
|
} catch (err) {
|
||||||
|
const stack = (err?.stack ?? err.message).split("\n");
|
||||||
|
const error = stack.shift();
|
||||||
|
logger.error(
|
||||||
|
"hf:main",
|
||||||
|
`Failed to self-delete message: ${error}\n\t${stack.join("\n\t")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
bot.on("interactionCreate", async (interaction) => {
|
||||||
|
try {
|
||||||
|
if (!(interaction.channel instanceof Dysnomia.Channel)) {
|
||||||
|
const newChannel = hf.bot.getChannel(interaction.channel.id);
|
||||||
|
if (newChannel) {
|
||||||
|
interaction.channel = newChannel;
|
||||||
|
} else {
|
||||||
|
interaction.channel = await hf.bot.getRESTChannel(
|
||||||
|
interaction.channel.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await InteractionDispatcher(interaction);
|
||||||
|
} catch (err) {
|
||||||
|
const stack = (err?.stack ?? err.message).split("\n");
|
||||||
|
const error = stack.shift();
|
||||||
|
logger.error(
|
||||||
|
"hf:main",
|
||||||
|
`Failed to dispatch interaction command: ${error}\n\t${stack.join(
|
||||||
|
"\n\t"
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -98,6 +184,27 @@ bot.once("ready", async () => {
|
||||||
bot.on("ready", () => {
|
bot.on("ready", () => {
|
||||||
logger.info("hf:main", "Reconnected to Discord.");
|
logger.info("hf:main", "Reconnected to Discord.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const commands = await bot.getCommands();
|
||||||
|
for (const command of interactionCommands.values()) {
|
||||||
|
const hasCommand = commands.find((c) => c.name == command.name);
|
||||||
|
if (hasCommand) continue;
|
||||||
|
|
||||||
|
await bot.createCommand({
|
||||||
|
name: command.name,
|
||||||
|
type: command.type,
|
||||||
|
description: command.helpText,
|
||||||
|
options: Object.values(command.options),
|
||||||
|
defaultMemberPermissions: command.permissions,
|
||||||
|
dmPermission: !command.guildOnly,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const command of commands) {
|
||||||
|
if (interactionCommands.has(command.name)) continue;
|
||||||
|
|
||||||
|
await bot.deleteCommand(command.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
bot.on("error", (err) => {
|
bot.on("error", (err) => {
|
||||||
|
|
26
src/lib/interactionCommand.js
Normal file
26
src/lib/interactionCommand.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const {ApplicationCommandTypes, ApplicationCommandOptionTypes} =
|
||||||
|
require("@projectdysnomia/dysnomia").Constants;
|
||||||
|
|
||||||
|
class InteractionCommand {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = ApplicationCommandTypes.CHAT_INPUT;
|
||||||
|
this.helpText = "No description provided.";
|
||||||
|
this.guildOnly = false;
|
||||||
|
this.options = {
|
||||||
|
send: {
|
||||||
|
type: ApplicationCommandOptionTypes.BOOLEAN,
|
||||||
|
name: "send",
|
||||||
|
description: "Should the output be ephemeral or not",
|
||||||
|
required: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
callback() {
|
||||||
|
return "Callback not overwritten.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = InteractionCommand;
|
127
src/lib/interactionDispatcher.js
Normal file
127
src/lib/interactionDispatcher.js
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
const logger = require("./logger.js");
|
||||||
|
const {MessageFlags} = require("@projectdysnomia/dysnomia").Constants;
|
||||||
|
const {pastelize, getTopColor} = require("./utils.js");
|
||||||
|
|
||||||
|
function getOption(interaction, command, key) {
|
||||||
|
return (
|
||||||
|
interaction.data.options?.find((o) => o.name === key)?.value ??
|
||||||
|
command.options[key].default
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runCommand(interaction, command) {
|
||||||
|
if (command.ownerOnly && interaction.user.id != hf.config.owner_id) {
|
||||||
|
return {
|
||||||
|
content: "No\n\nSent from my iPhone.",
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
command.elevatedOnly &&
|
||||||
|
!hf.config.elevated.includes(interaction.user.id)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
content: "No\n\nSent from my iPhone.",
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ret = command.callback(interaction);
|
||||||
|
if (ret instanceof Promise) {
|
||||||
|
return await ret;
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("hf:cmd:" + command.name, err + "\n" + err.stack);
|
||||||
|
return {
|
||||||
|
content: ":warning: An internal error occurred.",
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function InteractionDispatcher(interaction) {
|
||||||
|
const command = hf.interactionCommands.get(interaction.data.name);
|
||||||
|
const shouldSend = getOption(interaction, command, "send");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await runCommand(interaction, command);
|
||||||
|
if (response != null) {
|
||||||
|
if (response.file) {
|
||||||
|
const newFile = response.file;
|
||||||
|
delete response.file;
|
||||||
|
if (newFile.contents) {
|
||||||
|
newFile.file = newFile.contents;
|
||||||
|
delete newFile.contents;
|
||||||
|
}
|
||||||
|
if (newFile.name) {
|
||||||
|
newFile.filename = newFile.name;
|
||||||
|
delete newFile.name;
|
||||||
|
}
|
||||||
|
const files = response.attachments ?? [];
|
||||||
|
files.push(newFile);
|
||||||
|
response.attachments = files;
|
||||||
|
}
|
||||||
|
if (response.files) {
|
||||||
|
response.attachments = response.files;
|
||||||
|
delete response.files;
|
||||||
|
for (const attachment of response.attachments) {
|
||||||
|
if (attachment.contents) {
|
||||||
|
attachment.file = attachment.contents;
|
||||||
|
delete attachment.contents;
|
||||||
|
}
|
||||||
|
if (attachment.name) {
|
||||||
|
attachment.filename = attachment.name;
|
||||||
|
delete attachment.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (response.embed) {
|
||||||
|
response.embeds = [...(response.embeds ?? []), response.embed];
|
||||||
|
delete response.embed;
|
||||||
|
}
|
||||||
|
if (response.embeds) {
|
||||||
|
for (const embed of response.embeds) {
|
||||||
|
embed.color =
|
||||||
|
embed.color ??
|
||||||
|
getTopColor(interaction, hf.bot.user.id, pastelize(hf.bot.user.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await interaction.createMessage(
|
||||||
|
Object.assign(
|
||||||
|
typeof response === "string" ? {content: response} : response,
|
||||||
|
{
|
||||||
|
flags: shouldSend ? response.flags : MessageFlags.EPHEMERAL,
|
||||||
|
allowedMentions: {
|
||||||
|
repliedUser: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
await interaction.createMessage({
|
||||||
|
content: `:warning: An error has occurred:\n\`\`\`${err}\`\`\``,
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
allowedMentions: {
|
||||||
|
repliedUser: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
await interaction.createMessage({
|
||||||
|
content: `:warning: An error has occurred:\n\`\`\`${err}\`\`\``,
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
allowedMentions: {
|
||||||
|
repliedUser: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {InteractionDispatcher, getOption};
|
|
@ -28,7 +28,7 @@ async function processFile(link, spoiler = false) {
|
||||||
const file = await res.text();
|
const file = await res.text();
|
||||||
const lines = file.replace(/\r/g, "").split("\n");
|
const lines = file.replace(/\r/g, "").split("\n");
|
||||||
|
|
||||||
const fileName = link.substring(
|
const fileName = decodeURI(link).substring(
|
||||||
link.lastIndexOf("/") + 1,
|
link.lastIndexOf("/") + 1,
|
||||||
link.indexOf("#") == -1 ? link.length : link.indexOf("#")
|
link.indexOf("#") == -1 ? link.length : link.indexOf("#")
|
||||||
);
|
);
|
||||||
|
@ -155,40 +155,3 @@ events.add("messageCreate", "codePreviews", async function (msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: maybe all command outputs should have this ability
|
|
||||||
events.add(
|
|
||||||
"messageReactionAdd",
|
|
||||||
"codePreviews",
|
|
||||||
async function (msg, reaction, reactor) {
|
|
||||||
if (!msg.guildID) return;
|
|
||||||
if (!(await hasFlag(msg.guildID, "codePreviews"))) return;
|
|
||||||
if (reaction.name != "\u274c") return;
|
|
||||||
|
|
||||||
let channel = msg.channel;
|
|
||||||
if (!channel.name) {
|
|
||||||
channel = hf.bot.getChannel(channel.id);
|
|
||||||
}
|
|
||||||
if (!msg.messageReference) {
|
|
||||||
msg = await channel.getMessage(msg.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!msg.messageReference) return;
|
|
||||||
|
|
||||||
const ref = await channel.getMessage(msg.messageReference.messageID);
|
|
||||||
if (!ref) return;
|
|
||||||
if (
|
|
||||||
ref.author.id != reactor.id &&
|
|
||||||
!channel.permissionsOf(reactor.id).has("manageMessages")
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
if (
|
|
||||||
!REGEX_GITHUB.test(ref.content) &&
|
|
||||||
!REGEX_GITLAB.test(ref.content) &&
|
|
||||||
!REGEX_GITEA.test(ref.content)
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await msg.delete("Author requested code preview deletion");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const {MessageFlags} = require("@projectdysnomia/dysnomia").Constants;
|
const {MessageFlags, ApplicationCommandOptionTypes} =
|
||||||
|
require("@projectdysnomia/dysnomia").Constants;
|
||||||
const fs = require("node:fs");
|
const fs = require("node:fs");
|
||||||
const path = require("node:path");
|
const path = require("node:path");
|
||||||
const httpSignature = require("@peertube/http-signature");
|
const httpSignature = require("@peertube/http-signature");
|
||||||
|
@ -7,6 +8,8 @@ const events = require("../lib/events.js");
|
||||||
const logger = require("../lib/logger.js");
|
const logger = require("../lib/logger.js");
|
||||||
const {hasFlag} = require("../lib/guildSettings.js");
|
const {hasFlag} = require("../lib/guildSettings.js");
|
||||||
const {parseHtmlEntities, getUploadLimit} = require("../lib/utils.js");
|
const {parseHtmlEntities, getUploadLimit} = require("../lib/utils.js");
|
||||||
|
const InteractionCommand = require("../lib/interactionCommand.js");
|
||||||
|
const {getOption} = require("../lib/interactionDispatcher.js");
|
||||||
|
|
||||||
const FRIENDLY_USERAGENT =
|
const FRIENDLY_USERAGENT =
|
||||||
"HiddenPhox/fedimbed (https://gitdab.com/Cynosphere/HiddenPhox)";
|
"HiddenPhox/fedimbed (https://gitdab.com/Cynosphere/HiddenPhox)";
|
||||||
|
@ -157,7 +160,7 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
invalidUrl = true;
|
invalidUrl = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalidUrl) return;
|
if (invalidUrl) return {};
|
||||||
|
|
||||||
// some lemmy instances have old reddit frontend subdomains
|
// some lemmy instances have old reddit frontend subdomains
|
||||||
// but these frontends are just frontends and dont actually expose the API
|
// but these frontends are just frontends and dont actually expose the API
|
||||||
|
@ -661,7 +664,7 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
"fedimbed",
|
"fedimbed",
|
||||||
`Bailing trying to re-embed "${url}": Failed to get author.`
|
`Bailing trying to re-embed "${url}": Failed to get author.`
|
||||||
);
|
);
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start constructing embed
|
// Start constructing embed
|
||||||
|
@ -806,12 +809,16 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
let sendWait = false;
|
let sendWait = false;
|
||||||
if (videos.length > 0 || audios.length > 0 || images.length > 4) {
|
if (videos.length > 0 || audios.length > 0 || images.length > 4) {
|
||||||
sendWait = true;
|
sendWait = true;
|
||||||
await msg.addReaction("\uD83D\uDCE4");
|
if (msg) await msg.addReaction("\uD83D\uDCE4");
|
||||||
}
|
}
|
||||||
|
|
||||||
const embeds = [];
|
const embeds = [];
|
||||||
const files = [];
|
const files = [];
|
||||||
|
|
||||||
|
const guild =
|
||||||
|
msg.channel?.guild ??
|
||||||
|
(msg.guildID ? hf.bot.guilds.get(msg.guildID) : false);
|
||||||
|
|
||||||
if (images.length > 0) {
|
if (images.length > 0) {
|
||||||
if (images.length <= 4) {
|
if (images.length <= 4) {
|
||||||
for (const attachment of images) {
|
for (const attachment of images) {
|
||||||
|
@ -830,7 +837,7 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
},
|
},
|
||||||
}).then((res) => Number(res.headers.get("Content-Length")));
|
}).then((res) => Number(res.headers.get("Content-Length")));
|
||||||
|
|
||||||
if (size <= getUploadLimit(msg.channel.guild)) {
|
if (size <= getUploadLimit(guild)) {
|
||||||
const file = await fetch(attachment.url, {
|
const file = await fetch(attachment.url, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": FRIENDLY_USERAGENT,
|
"User-Agent": FRIENDLY_USERAGENT,
|
||||||
|
@ -864,7 +871,7 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
},
|
},
|
||||||
}).then((res) => Number(res.headers.get("Content-Length")));
|
}).then((res) => Number(res.headers.get("Content-Length")));
|
||||||
|
|
||||||
if (size <= getUploadLimit(msg.channel.guild)) {
|
if (size <= getUploadLimit(guild)) {
|
||||||
const file = await fetch(attachment.url, {
|
const file = await fetch(attachment.url, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": FRIENDLY_USERAGENT,
|
"User-Agent": FRIENDLY_USERAGENT,
|
||||||
|
@ -937,7 +944,7 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
},
|
},
|
||||||
}).then((res) => Number(res.headers.get("Content-Length")));
|
}).then((res) => Number(res.headers.get("Content-Length")));
|
||||||
|
|
||||||
if (size <= getUploadLimit(msg.channel.guild)) {
|
if (size <= getUploadLimit(guild)) {
|
||||||
const file = await fetch(attachment.url, {
|
const file = await fetch(attachment.url, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": FRIENDLY_USERAGENT,
|
"User-Agent": FRIENDLY_USERAGENT,
|
||||||
|
@ -968,7 +975,7 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
},
|
},
|
||||||
}).then((res) => Number(res.headers.get("Content-Length")));
|
}).then((res) => Number(res.headers.get("Content-Length")));
|
||||||
|
|
||||||
if (size <= getUploadLimit(msg.channel.guild)) {
|
if (size <= getUploadLimit(guild)) {
|
||||||
const file = await fetch(attachment.url, {
|
const file = await fetch(attachment.url, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": FRIENDLY_USERAGENT,
|
"User-Agent": FRIENDLY_USERAGENT,
|
||||||
|
@ -995,8 +1002,8 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await msg.channel
|
return {
|
||||||
.createMessage({
|
response: {
|
||||||
content:
|
content:
|
||||||
cw != "" &&
|
cw != "" &&
|
||||||
(images.length > 0 || videos.length > 0 || audios.length > 0)
|
(images.length > 0 || videos.length > 0 || audios.length > 0)
|
||||||
|
@ -1012,16 +1019,9 @@ async function processUrl(msg, url, spoiler = false) {
|
||||||
messageReference: {
|
messageReference: {
|
||||||
messageID: msg.id,
|
messageID: msg.id,
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
.then(() => {
|
sendWait,
|
||||||
if (sendWait) {
|
};
|
||||||
msg.removeReaction("\uD83D\uDCE4");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((msg.flags & MessageFlags.SUPPRESS_EMBEDS) === 0) {
|
|
||||||
msg.edit({flags: MessageFlags.SUPPRESS_EMBEDS}).catch(() => {});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
events.add("messageCreate", "fedimbed", async function (msg) {
|
events.add("messageCreate", "fedimbed", async function (msg) {
|
||||||
|
@ -1054,15 +1054,100 @@ events.add("messageCreate", "fedimbed", async function (msg) {
|
||||||
"fedimbed",
|
"fedimbed",
|
||||||
`Hit "${service}" for "${url}", processing now.`
|
`Hit "${service}" for "${url}", processing now.`
|
||||||
);
|
);
|
||||||
await processUrl(msg, url, hasSpoiler).catch((err) => {
|
try {
|
||||||
|
const {response, sendWait} = await processUrl(msg, url, hasSpoiler);
|
||||||
|
await msg.channel.createMessage(response).then(() => {
|
||||||
|
if (sendWait) {
|
||||||
|
msg.removeReaction("\uD83D\uDCE4");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((msg.flags & MessageFlags.SUPPRESS_EMBEDS) === 0) {
|
||||||
|
msg.edit({flags: MessageFlags.SUPPRESS_EMBEDS}).catch(() => {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
"fedimbed",
|
"fedimbed",
|
||||||
`Error processing "${url}":\n` + err.stack
|
`Error processing "${url}":\n` + err.stack
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const fedimbedCommand = new InteractionCommand("fedimbed");
|
||||||
|
fedimbedCommand.helpText =
|
||||||
|
"Better embeds for fediverse (Mastodon, Pleroma, etc) posts";
|
||||||
|
fedimbedCommand.options.url = {
|
||||||
|
name: "url",
|
||||||
|
type: ApplicationCommandOptionTypes.STRING,
|
||||||
|
description: "URL to attempt to parse for re-embedding",
|
||||||
|
required: true,
|
||||||
|
default: "",
|
||||||
|
};
|
||||||
|
fedimbedCommand.options.spoiler = {
|
||||||
|
name: "spoiler",
|
||||||
|
type: ApplicationCommandOptionTypes.BOOLEAN,
|
||||||
|
description: "Send embed spoilered",
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
};
|
||||||
|
fedimbedCommand.callback = async function (interaction) {
|
||||||
|
let url = getOption(interaction, fedimbedCommand, "url");
|
||||||
|
const spoiler = getOption(interaction, fedimbedCommand, "spoiler");
|
||||||
|
|
||||||
|
url = url
|
||||||
|
.replace(/\|/g, "")
|
||||||
|
.replace(/^\]\(/, "")
|
||||||
|
.replace(/\s*[\S]*?\)$/, "")
|
||||||
|
.trim()
|
||||||
|
.replace("@\u200b", "@")
|
||||||
|
.replace("@%E2%80%8B", "@");
|
||||||
|
let urlObj;
|
||||||
|
try {
|
||||||
|
urlObj = new URL(url);
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
content: `Failed to parse URL:\`\`\`\n${err}\`\`\``,
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasService = false;
|
||||||
|
for (const service of Object.keys(PATH_REGEX)) {
|
||||||
|
const regex = PATH_REGEX[service];
|
||||||
|
if (urlObj && regex.test(urlObj.pathname)) {
|
||||||
|
hasService = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasService) {
|
||||||
|
try {
|
||||||
|
const {response} = await processUrl(interaction, url, spoiler);
|
||||||
|
|
||||||
|
if (!response)
|
||||||
|
return {
|
||||||
|
content: "Failed to process URL.",
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
delete response.messageReference;
|
||||||
|
return response;
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("fedimbed", `Error processing "${url}":\n` + err.stack);
|
||||||
|
return {
|
||||||
|
content: "Failed to process URL.",
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
content: "Did not get a valid service for this URL.",
|
||||||
|
flags: MessageFlags.EPHEMERAL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue