Added gif, detect if any image servers are disconnected
This commit is contained in:
parent
0fbc165154
commit
41c8be04cf
7 changed files with 523 additions and 437 deletions
|
@ -52,7 +52,7 @@ class ImageCommand extends Command {
|
||||||
|
|
||||||
if (this.constructor.requiresImage) {
|
if (this.constructor.requiresImage) {
|
||||||
try {
|
try {
|
||||||
const image = await imageDetect(this.client, this.message);
|
const image = await imageDetect(this.client, this.message, true);
|
||||||
if (image === undefined) {
|
if (image === undefined) {
|
||||||
collections.runningCommands.delete(this.message.author.id);
|
collections.runningCommands.delete(this.message.author.id);
|
||||||
return this.constructor.noImage;
|
return this.constructor.noImage;
|
||||||
|
@ -61,7 +61,7 @@ class ImageCommand extends Command {
|
||||||
return "That image is too large!";
|
return "That image is too large!";
|
||||||
} else if (image.type === "tenorlimit") {
|
} else if (image.type === "tenorlimit") {
|
||||||
collections.runningCommands.delete(this.message.author.id);
|
collections.runningCommands.delete(this.message.author.id);
|
||||||
return "I've been rate-limited by Tenor. Please try uploading the GIF elsewhere.";
|
return "I've been rate-limited by Tenor. Please try uploading your GIF elsewhere.";
|
||||||
}
|
}
|
||||||
magickParams.path = image.path;
|
magickParams.path = image.path;
|
||||||
magickParams.type = image.type;
|
magickParams.type = image.type;
|
||||||
|
|
16
commands/general/gif.js
Normal file
16
commands/general/gif.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const Command = require("../../classes/command.js");
|
||||||
|
const imageDetect = require("../../utils/imagedetect.js");
|
||||||
|
|
||||||
|
class GifCommand extends Command {
|
||||||
|
async run() {
|
||||||
|
this.message.channel.sendTyping();
|
||||||
|
const image = await imageDetect(this.client, this.message);
|
||||||
|
if (image === undefined) return "You need to provide an image with a QR code to read!";
|
||||||
|
return image.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static description = "Gets a direct GIF URL (useful for saving GIFs from sites like Tenor)";
|
||||||
|
static aliases = ["getgif", "giflink"];
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = GifCommand;
|
|
@ -13,6 +13,7 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
|
||||||
Napi::Object obj = info[0].As<Napi::Object>();
|
Napi::Object obj = info[0].As<Napi::Object>();
|
||||||
Napi::Buffer<char> data = obj.Get("data").As<Napi::Buffer<char>>();
|
Napi::Buffer<char> data = obj.Get("data").As<Napi::Buffer<char>>();
|
||||||
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
|
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
|
||||||
|
float pos = obj.Has("pos") ? obj.Get("pos").As<Napi::Number>().FloatValue() : 0.5;
|
||||||
string type = obj.Get("type").As<Napi::String>().Utf8Value();
|
string type = obj.Get("type").As<Napi::String>().Utf8Value();
|
||||||
int delay =
|
int delay =
|
||||||
obj.Has("delay") ? obj.Get("delay").As<Napi::Number>().Int32Value() : 0;
|
obj.Has("delay") ? obj.Get("delay").As<Napi::Number>().Int32Value() : 0;
|
||||||
|
@ -26,6 +27,7 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
|
||||||
readImages(&frames, Blob(data.Data(), data.Length()));
|
readImages(&frames, Blob(data.Data(), data.Length()));
|
||||||
|
|
||||||
size_t width = frames.front().baseColumns();
|
size_t width = frames.front().baseColumns();
|
||||||
|
size_t height = frames.front().baseRows();
|
||||||
string query(to_string(width - ((width / 25) * 2)) + "x");
|
string query(to_string(width - ((width / 25) * 2)) + "x");
|
||||||
Image caption_image(Geometry(query), Color("none"));
|
Image caption_image(Geometry(query), Color("none"));
|
||||||
caption_image.backgroundColor(Color("none"));
|
caption_image.backgroundColor(Color("none"));
|
||||||
|
@ -42,7 +44,7 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
|
||||||
|
|
||||||
for (Image &image : coalesced) {
|
for (Image &image : coalesced) {
|
||||||
list<Image> images;
|
list<Image> images;
|
||||||
image.composite(caption_image, Magick::CenterGravity,
|
image.composite(caption_image, 0, height * pos,
|
||||||
Magick::OverCompositeOp);
|
Magick::OverCompositeOp);
|
||||||
image.magick(type);
|
image.magick(type);
|
||||||
image.animationDelay(delay == 0 ? image.animationDelay() : delay);
|
image.animationDelay(delay == 0 ? image.animationDelay() : delay);
|
||||||
|
|
900
package-lock.json
generated
900
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,7 @@
|
||||||
"file-type": "^16.1.0",
|
"file-type": "^16.1.0",
|
||||||
"jsqr": "^1.3.1",
|
"jsqr": "^1.3.1",
|
||||||
"lavacord": "^1.1.9",
|
"lavacord": "^1.1.9",
|
||||||
"node-addon-api": "^3.1.0",
|
"node-addon-api": "^3.2.1",
|
||||||
"node-emoji": "^1.10.0",
|
"node-emoji": "^1.10.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"qrcode": "^1.4.4",
|
"qrcode": "^1.4.4",
|
||||||
|
|
|
@ -123,10 +123,10 @@ exports.disconnect = async () => {
|
||||||
|
|
||||||
const getIdeal = async () => {
|
const getIdeal = async () => {
|
||||||
let serversLeft = this.connections.size;
|
let serversLeft = this.connections.size;
|
||||||
if (serversLeft === 0) {
|
if (serversLeft < this.servers.length) {
|
||||||
for (const server of this.servers) {
|
for (const server of this.servers) {
|
||||||
try {
|
try {
|
||||||
await this.connect(server);
|
if (!this.connections.has(server)) await this.connect(server);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ exports.check = (cmd) => {
|
||||||
return magick[cmd] ? true : false;
|
return magick[cmd] ? true : false;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.getType = async (image) => {
|
exports.getType = async (image, extraReturnTypes) => {
|
||||||
if (!image.startsWith("http")) {
|
if (!image.startsWith("http")) {
|
||||||
const imageType = await fileType.fromFile(image);
|
const imageType = await fileType.fromFile(image);
|
||||||
if (imageType && formats.includes(imageType.mime)) {
|
if (imageType && formats.includes(imageType.mime)) {
|
||||||
|
@ -214,7 +214,7 @@ exports.getType = async (image) => {
|
||||||
});
|
});
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
const size = imageRequest.headers.has("Content-Range") ? imageRequest.headers.get("Content-Range").split("/")[1] : imageRequest.headers.get("Content-Length");
|
const size = imageRequest.headers.has("Content-Range") ? imageRequest.headers.get("Content-Range").split("/")[1] : imageRequest.headers.get("Content-Length");
|
||||||
if (parseInt(size) > 26214400) { // 25 MB
|
if (parseInt(size) > 26214400 && extraReturnTypes) { // 25 MB
|
||||||
type = "large";
|
type = "large";
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ const imageFormats = ["image/jpeg", "image/png", "image/webp", "image/gif"];
|
||||||
const videoFormats = ["video/mp4", "video/webm", "video/mov"];
|
const videoFormats = ["video/mp4", "video/webm", "video/mov"];
|
||||||
|
|
||||||
// gets the proper image paths
|
// gets the proper image paths
|
||||||
const getImage = async (image, image2, video, gifv = false) => {
|
const getImage = async (image, image2, video, extraReturnTypes, gifv = false) => {
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
url: image2,
|
url: image2,
|
||||||
|
@ -48,7 +48,7 @@ const getImage = async (image, image2, video, gifv = false) => {
|
||||||
// Note that MP4 conversion requires an ImageMagick build that supports MPEG decoding
|
// Note that MP4 conversion requires an ImageMagick build that supports MPEG decoding
|
||||||
if (process.env.TENOR !== "") {
|
if (process.env.TENOR !== "") {
|
||||||
const data = await fetch(`https://g.tenor.com/v1/gifs?ids=${image2.split("-").pop()}&media_filter=minimal&limit=1&key=${process.env.TENOR}`);
|
const data = await fetch(`https://g.tenor.com/v1/gifs?ids=${image2.split("-").pop()}&media_filter=minimal&limit=1&key=${process.env.TENOR}`);
|
||||||
if (data.status === 429) return "tenorlimit";
|
if (data.status === 429) return extraReturnTypes ? "tenorlimit" : null;
|
||||||
const json = await data.json();
|
const json = await data.json();
|
||||||
payload.path = json.results[0].media[0].gif.url;
|
payload.path = json.results[0].media[0].gif.url;
|
||||||
} else {
|
} else {
|
||||||
|
@ -69,10 +69,10 @@ const getImage = async (image, image2, video, gifv = false) => {
|
||||||
}
|
}
|
||||||
payload.type = "image/gif";
|
payload.type = "image/gif";
|
||||||
} else if (video) {
|
} else if (video) {
|
||||||
payload.type = await getType(payload.path);
|
payload.type = await getType(payload.path, extraReturnTypes);
|
||||||
if (!payload.type || (!videoFormats.includes(payload.type) && !imageFormats.includes(payload.type))) return;
|
if (!payload.type || (!videoFormats.includes(payload.type) && !imageFormats.includes(payload.type))) return;
|
||||||
} else {
|
} else {
|
||||||
payload.type = await getType(payload.path);
|
payload.type = await getType(payload.path, extraReturnTypes);
|
||||||
if (!payload.type || !imageFormats.includes(payload.type)) return;
|
if (!payload.type || !imageFormats.includes(payload.type)) return;
|
||||||
}
|
}
|
||||||
return payload;
|
return payload;
|
||||||
|
@ -85,22 +85,22 @@ const getImage = async (image, image2, video, gifv = false) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkImages = async (message, video) => {
|
const checkImages = async (message, extraReturnTypes, video) => {
|
||||||
let type;
|
let type;
|
||||||
// first check the embeds
|
// first check the embeds
|
||||||
if (message.embeds.length !== 0) {
|
if (message.embeds.length !== 0) {
|
||||||
// embeds can vary in types, we check for tenor gifs first
|
// embeds can vary in types, we check for tenor gifs first
|
||||||
if (message.embeds[0].type === "gifv") {
|
if (message.embeds[0].type === "gifv") {
|
||||||
type = await getImage(message.embeds[0].video.url, message.embeds[0].url, video, true);
|
type = await getImage(message.embeds[0].video.url, message.embeds[0].url, video, extraReturnTypes, true);
|
||||||
// then we check for other image types
|
// then we check for other image types
|
||||||
} else if ((message.embeds[0].type === "video" || message.embeds[0].type === "image") && message.embeds[0].thumbnail) {
|
} else if ((message.embeds[0].type === "video" || message.embeds[0].type === "image") && message.embeds[0].thumbnail) {
|
||||||
type = await getImage(message.embeds[0].thumbnail.proxy_url, message.embeds[0].thumbnail.url, video);
|
type = await getImage(message.embeds[0].thumbnail.proxy_url, message.embeds[0].thumbnail.url, video, extraReturnTypes);
|
||||||
// finally we check both possible image fields for "generic" embeds
|
// finally we check both possible image fields for "generic" embeds
|
||||||
} else if (message.embeds[0].type === "rich") {
|
} else if (message.embeds[0].type === "rich") {
|
||||||
if (message.embeds[0].thumbnail) {
|
if (message.embeds[0].thumbnail) {
|
||||||
type = await getImage(message.embeds[0].thumbnail.proxy_url, message.embeds[0].thumbnail.url, video);
|
type = await getImage(message.embeds[0].thumbnail.proxy_url, message.embeds[0].thumbnail.url, video, extraReturnTypes);
|
||||||
} else if (message.embeds[0].image) {
|
} else if (message.embeds[0].image) {
|
||||||
type = await getImage(message.embeds[0].image.proxy_url, message.embeds[0].image.url, video);
|
type = await getImage(message.embeds[0].image.proxy_url, message.embeds[0].image.url, video, extraReturnTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// then check the attachments
|
// then check the attachments
|
||||||
|
@ -112,23 +112,23 @@ const checkImages = async (message, video) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// this checks for the latest message containing an image and returns the url of the image
|
// this checks for the latest message containing an image and returns the url of the image
|
||||||
module.exports = async (client, cmdMessage, video = false) => {
|
module.exports = async (client, cmdMessage, extraReturnTypes = false, video = false) => {
|
||||||
// we start by checking if the message is a reply to another message
|
// we start by checking if the message is a reply to another message
|
||||||
if (cmdMessage.messageReference) {
|
if (cmdMessage.messageReference) {
|
||||||
const replyMessage = await client.getMessage(cmdMessage.messageReference.channelID, cmdMessage.messageReference.messageID).catch(() => undefined);
|
const replyMessage = await client.getMessage(cmdMessage.messageReference.channelID, cmdMessage.messageReference.messageID).catch(() => undefined);
|
||||||
if (replyMessage) {
|
if (replyMessage) {
|
||||||
const replyResult = await checkImages(replyMessage, video);
|
const replyResult = await checkImages(replyMessage, extraReturnTypes, video);
|
||||||
if (replyResult !== false) return replyResult;
|
if (replyResult !== false) return replyResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// then we check the current message
|
// then we check the current message
|
||||||
const result = await checkImages(cmdMessage, video);
|
const result = await checkImages(cmdMessage, extraReturnTypes, video);
|
||||||
if (result !== false) return result;
|
if (result !== false) return result;
|
||||||
// if there aren't any replies then iterate over the last few messages in the channel
|
// if there aren't any replies then iterate over the last few messages in the channel
|
||||||
const messages = await client.getMessages(cmdMessage.channel.id);
|
const messages = await client.getMessages(cmdMessage.channel.id);
|
||||||
// iterate over each message
|
// iterate over each message
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
const result = await checkImages(message, video);
|
const result = await checkImages(message, extraReturnTypes, video);
|
||||||
if (result === false) {
|
if (result === false) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue