mrmBot-Matrix/classes/imageCommand.js

164 lines
5.8 KiB
JavaScript
Raw Normal View History

2023-03-15 14:09:09 +00:00
import Command from "./command.js";
import imageDetect from "../utils/imagedetect.js";
import { runImageJob } from "../utils/image.js";
import { runningCommands } from "../utils/collections.js";
import { readFileSync } from "fs";
const { emotes } = JSON.parse(readFileSync(new URL("../config/messages.json", import.meta.url)));
import { random } from "../utils/misc.js";
import { selectedImages } from "../utils/collections.js";
class ImageCommand extends Command {
async criteria() {
return true;
}
async run() {
this.success = false;
const timestamp = this.type === "classic" ? this.message.createdAt : Math.floor((this.interaction.id / 4194304) + 1420070400000);
// check if this command has already been run in this channel with the same arguments, and we are awaiting its result
// if so, don't re-run it
if (runningCommands.has(this.author) && (new Date(runningCommands.get(this.author)) - new Date(timestamp)) < 5000) {
return "Please slow down a bit.";
}
// before awaiting the command result, add this command to the set of running commands
runningCommands.set(this.author, timestamp);
const imageParams = {
cmd: this.constructor.command,
params: {
togif: !!this.options.togif
},
id: this.message.event_id
};
2023-03-17 00:23:01 +00:00
// if (this.type === "application") // await this.acknowledge();
2023-03-15 14:09:09 +00:00
if (this.constructor.requiresImage) {
try {
const selection = selectedImages.get(this.author);
const image = await imageDetect(this.client, this.message, this.interaction, this.options, true);
if (selection) selectedImages.delete(this.author);
if (image === undefined) {
runningCommands.delete(this.author);
2023-03-17 00:40:15 +00:00
return `${this.constructor.noImage} (Tip: try running your command while replying to an image (or link to an image))`;
2023-03-15 14:09:09 +00:00
} else if (image.type === "large") {
runningCommands.delete(this.author);
return "That image is too large (>= 25MB)! Try using a smaller image.";
} else if (image.type === "tenorlimit") {
runningCommands.delete(this.author);
return "I've been rate-limited by Tenor. Please try uploading your GIF elsewhere.";
}
imageParams.path = image.path;
imageParams.params.type = image.type;
imageParams.url = image.url; // technically not required but can be useful for text filtering
imageParams.name = image.name;
if (this.constructor.requiresGIF) imageParams.onlyGIF = true;
} catch (e) {
runningCommands.delete(this.author);
throw e;
}
}
if (this.constructor.requiresText) {
const text = this.options.text ?? this.args.join(" ").trim();
if (text.length === 0 || !await this.criteria(text, imageParams.url)) {
runningCommands.delete(this.author);
return this.constructor.noText;
}
}
if (typeof this.params === "function") {
Object.assign(imageParams.params, this.params(imageParams.url, imageParams.name));
} else if (typeof this.params === "object") {
Object.assign(imageParams.params, this.params);
}
let status;
if (imageParams.params.type === "image/gif" && this.type === "classic") {
2023-03-17 01:19:39 +00:00
status = await this.processMessage(this.message.room_id);
2023-03-15 14:09:09 +00:00
}
try {
const { buffer, type, width, height } = await runImageJob(imageParams);
2023-03-15 14:09:09 +00:00
if (type === "nogif" && this.constructor.requiresGIF) {
return "That isn't a GIF!";
}
this.success = true;
return {
contents: buffer,
name: `${this.constructor.command}.${type}`,
type,
width,
height
2023-03-15 14:09:09 +00:00
};
} catch (e) {
if (e === "Request ended prematurely due to a closed connection") return "This image job couldn't be completed because the server it was running on went down. Try running your command again.";
if (e === "Job timed out" || e === "Timeout") return "The image is taking too long to process (>=15 minutes), so the job was cancelled. Try using a smaller image.";
if (e === "No available servers") return "I can't seem to contact the image servers, they might be down or still trying to start up. Please wait a little bit.";
throw e;
} finally {
try {
2023-03-17 01:19:39 +00:00
if (status) {
// TODO: tell status message to self-destruct
}
2023-03-15 14:09:09 +00:00
} catch {
// no-op
}
runningCommands.delete(this.author);
}
}
2023-03-17 01:19:39 +00:00
async processMessage(channel) {
2023-03-15 14:09:09 +00:00
this.client.send
const content = {
body: "Processing... This might take a while",
msgtype: "m.text",
};
2023-03-17 01:19:39 +00:00
return await this.client.sendEvent(channel, "m.room.message", content, "", (err, res) => {
2023-03-15 14:09:09 +00:00
logger.log("error", err)
});
}
static init() {
this.flags = [];
if (this.requiresText || this.textOptional) {
this.flags.push({
name: "text",
type: 3,
description: "The text to put on the image",
required: !this.textOptional
});
}
if (this.requiresImage) {
this.flags.push({
name: "image",
type: 11,
description: "An image/GIF attachment"
}, {
name: "link",
type: 3,
description: "An image/GIF URL"
});
}
this.flags.push({
name: "togif",
type: 5,
description: "Force GIF output"
});
return this;
}
static allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times", "comic sans ms"];
static requiresImage = true;
static requiresText = false;
static textOptional = false;
static requiresGIF = false;
static noImage = "You need to provide an image/GIF!";
static noText = "You need to provide some text!";
static command = "";
}
export default ImageCommand;