95 lines
3.7 KiB
JavaScript
95 lines
3.7 KiB
JavaScript
const fetch = require("node-fetch");
|
|
const AbortController = require("abort-controller");
|
|
const fileType = require("file-type");
|
|
const { promisify } = require("util");
|
|
const { writeFile } = require("fs").promises;
|
|
const execPromise = promisify(require("child_process").exec);
|
|
const urlRegex = /(?:\w+:)?\/\/(\S+)/;
|
|
|
|
// this checks if the file is, in fact, an image
|
|
const typeCheck = async (image, image2, gifv = false) => {
|
|
// download the file to a buffer
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => {
|
|
controller.abort();
|
|
}, 25000);
|
|
try {
|
|
const imageRequest = await fetch(image, { signal: controller.signal });
|
|
const imageBuffer = await imageRequest.buffer();
|
|
if (imageBuffer.size >= 25 * 1024 * 1024) return;
|
|
// get the file type
|
|
const imageType = await fileType.fromBuffer(imageBuffer);
|
|
// check if the file is a jpeg, png, or webp
|
|
const formats = ["image/jpeg", "image/png", "image/webp", "image/gif"];
|
|
if (gifv) formats.push("video/mp4");
|
|
if (imageType && formats.includes(imageType.mime)) {
|
|
// if it is, then return the url with the file type
|
|
const path = `/tmp/${Math.random().toString(36).substring(2, 15)}.${imageType.ext}`;
|
|
await writeFile(path, imageBuffer);
|
|
const payload = {
|
|
type: imageType.ext !== "mp4" ? (imageType.ext === "jpg" ? "jpeg" : imageType.ext) : "gif",
|
|
path: path,
|
|
url: image2
|
|
};
|
|
if (payload.type === "gif") payload.delay = (await execPromise(`ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate ${path}`)).stdout.replace("\n", "");
|
|
return payload;
|
|
} else {
|
|
// if not, then return false
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
if (error.name === "AbortError") {
|
|
throw Error("Timed out");
|
|
} else {
|
|
throw error;
|
|
}
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
};
|
|
|
|
const checkImages = async (message) => {
|
|
let type;
|
|
// first check the embeds
|
|
if (message.embeds.length !== 0) {
|
|
// embeds can have 2 possible entries with images, we check the thumbnail first
|
|
if (message.embeds[0].type === "gifv") {
|
|
type = await typeCheck(message.embeds[0].video.url, message.embeds[0].video.url, true);
|
|
} else if (message.embeds[0].thumbnail) {
|
|
type = await typeCheck(message.embeds[0].thumbnail.proxy_url, message.embeds[0].thumbnail.url);
|
|
// if there isn't a thumbnail check the image area
|
|
} else if (message.embeds[0].image) {
|
|
type = await typeCheck(message.embeds[0].image.proxy_url, message.embeds[0].image.url);
|
|
}
|
|
// then check the attachments
|
|
} else if (message.attachments.length !== 0) {
|
|
// get type of file
|
|
type = await typeCheck(message.attachments[0].proxy_url, message.attachments[0].url);
|
|
// if there's nothing in the attachments check the urls in the message if there are any
|
|
} else if (urlRegex.test(message.content)) {
|
|
// get url
|
|
const url = message.content.match(urlRegex);
|
|
// get type of file
|
|
type = await typeCheck(url[0], url[0]);
|
|
}
|
|
// if the file is an image then return it
|
|
return type ? type : false;
|
|
};
|
|
|
|
// this checks for the latest message containing an image and returns the url of the image
|
|
module.exports = async (cmdMessage) => {
|
|
// we start by checking the current message for images
|
|
const result = await checkImages(cmdMessage);
|
|
if (result !== false) return result;
|
|
// if there aren't any then iterate over the last few messages in the channel
|
|
const messages = await cmdMessage.channel.getMessages();
|
|
// iterate over each message
|
|
for (const message of messages) {
|
|
const result = await checkImages(message);
|
|
if (result === false) {
|
|
continue;
|
|
} else {
|
|
return result;
|
|
}
|
|
}
|
|
};
|