This repository has been archived on 2022-01-28. You can view files and clone it, but cannot push or open issues or pull requests.
beebot/index.js

270 lines
7.4 KiB
JavaScript
Raw Normal View History

2017-12-11 16:51:06 +01:00
var _ = require('lodash');
2017-12-07 03:30:56 +01:00
var express = require("express");
var request = require("request");
var Discord = require('discord.js');
const Canvas = require("canvas");
2017-12-10 15:03:09 +01:00
const Image = Canvas.Image;
2017-12-07 03:30:56 +01:00
const twemoji = require("./twemoji");
var app = express()
2017-12-11 16:51:06 +01:00
var config = require("./config.default.json");
try {
_.extend(config, require("./config"));
}catch(err) {
console.log("No config.json found!");
}
2017-12-07 03:30:56 +01:00
var cache = {};
2017-12-15 14:18:21 +01:00
function all(x, c) {
_.isArray(x) ? _.each(x,c) : c(x);
}
2017-12-11 16:43:28 +01:00
templates = config.templates;
2017-12-10 15:03:09 +01:00
for(templateName in templates) {
const data = templates[templateName];
2017-12-15 14:18:21 +01:00
all(data, template => {
template.image = new Image();
template.image.src = template.src;
})
2017-12-10 15:03:09 +01:00
}
2017-12-07 03:30:56 +01:00
2017-12-11 16:43:28 +01:00
// drawing: we keep the image fixed in its default position and draw the template on top/below it
// calculates the x or y position of the template to be drawn
// size = width or height of the template/image
// anchor = the corresponding anchor config
function calculatePosition(scale, anchor, imageSize) {
return imageSize * anchor.position / 100 - anchor.offset * scale;
}
2017-12-07 03:30:56 +01:00
2017-12-19 15:43:00 +01:00
function render(template, img, size, flipH) {
2017-12-15 14:18:21 +01:00
var imgWidth = img.width;
var imgHeight = img.height;
2017-12-10 15:56:37 +01:00
if (size && size.height) {
2017-12-15 14:18:21 +01:00
imgHeight = size.height;
if (!size.width) imgWidth = imgWidth * size.height / img.height;
2017-12-10 15:56:37 +01:00
}
if (size && size.width) {
2017-12-15 14:18:21 +01:00
imgWidth = size.width;
if (!size.height) imgHeight = imgHeight * size.width / img.width;
2017-12-10 15:56:37 +01:00
}
2017-12-07 03:30:56 +01:00
2017-12-15 14:18:21 +01:00
const xScale = imgWidth / template.anchor.x.size;
const yScale = imgHeight / template.anchor.y.size;
const templateScale = Math.max(0, Math.min(10, Math.max(xScale || 0, yScale || 0)));
console.log("templateScale",templateScale)
2017-12-07 03:30:56 +01:00
2017-12-15 14:18:21 +01:00
let templateOffsetX = calculatePosition(templateScale, template.anchor.x, imgWidth);
let templateOffsetY = calculatePosition(templateScale, template.anchor.y, imgHeight);
2017-12-07 03:30:56 +01:00
2017-12-11 16:43:28 +01:00
let imageOffsetX = 0;
let imageOffsetY = 0;
2017-12-15 14:18:21 +01:00
let resultingWidth = imgWidth; // start with the image boundaries as defined by the image
let resultingHeight = imgHeight;
2017-12-07 03:30:56 +01:00
2017-12-11 16:43:28 +01:00
if(templateOffsetX < 0) {
resultingWidth -= templateOffsetX;
imageOffsetX = -templateOffsetX;
templateOffsetX = 0;
2017-12-10 15:56:37 +01:00
}
2017-12-11 16:43:28 +01:00
if(templateOffsetY < 0) {
resultingHeight -= templateOffsetY;
imageOffsetY = -templateOffsetY;
templateOffsetY = 0;
}
2017-12-11 17:00:03 +01:00
if(templateOffsetX + template.image.width * templateScale > resultingWidth) {
resultingWidth = templateOffsetX + template.image.width * templateScale;
2017-12-11 16:43:28 +01:00
}
2017-12-11 17:00:03 +01:00
if(templateOffsetY + template.image.height * templateScale > resultingHeight) {
resultingHeight = templateOffsetY + template.image.height * templateScale;
2017-12-10 15:56:37 +01:00
}
2017-12-07 03:30:56 +01:00
2017-12-11 16:43:28 +01:00
const toDraw = [{
z: 1,
image: img,
2017-12-19 15:43:00 +01:00
x: flipH ? resultingWidth - imageOffsetX - imgWidth : imageOffsetX,
2017-12-11 16:43:28 +01:00
y: imageOffsetY,
2017-12-15 14:18:21 +01:00
h: imgHeight,
w: imgWidth,
2017-12-11 16:43:28 +01:00
name: "image"
}, {
z: template.z || 0,
image: template.image,
x: templateOffsetX,
y: templateOffsetY,
h: template.image.height * templateScale,
w: template.image.width * templateScale,
2017-12-19 15:43:00 +01:00
name: "template "+template.src,
flipH
2017-12-11 16:43:28 +01:00
}].sort((u,v) => u.z > v.z);
2017-12-10 15:56:37 +01:00
var canvas = new Canvas(resultingWidth, resultingHeight);
var ctx = canvas.getContext("2d");
2017-12-11 16:43:28 +01:00
for(let i=0;i<toDraw.length;++i) {
const subject = toDraw[i];
2017-12-19 15:43:00 +01:00
console.log("Drawing "+subject.name+(subject.flipH?" (flipped)":""))
2017-12-11 16:43:28 +01:00
try {
2017-12-19 15:43:00 +01:00
if(subject.flipH) {
ctx.save();
ctx.translate(resultingWidth, 0);
ctx.scale(-1, 1);
}
2017-12-11 16:43:28 +01:00
ctx.drawImage(subject.image, subject.x, subject.y, subject.w, subject.h);
2017-12-19 15:43:00 +01:00
if(subject.flipH) {
ctx.restore();
}
2017-12-11 16:43:28 +01:00
} catch (err) {
console.error(err);
throw new Error(JSON.stringify({ status: 400, error: "Invalid template" }))
}
2017-12-10 15:56:37 +01:00
}
2017-12-10 15:03:09 +01:00
2017-12-10 15:56:37 +01:00
// return the image and cache it
return(canvas);
2017-12-07 03:30:56 +01:00
}
2017-12-10 15:56:37 +01:00
app.get("/:templateName/", async function (req, res) {
2017-12-10 15:03:09 +01:00
if(!templates[req.params.templateName]) return res.status(404).end();
2017-12-10 23:42:10 +01:00
try {
const canvas = render(templates[req.params.templateName], await loadImage(req.query.url))
2017-12-07 03:30:56 +01:00
console.log(canvas)
res.setHeader('Content-Type', 'image/png');
2017-12-10 23:42:10 +01:00
return canvas.pngStream().pipe(res);
} catch(err) {
2017-12-11 16:43:28 +01:00
console.log(err);
2017-12-10 23:42:10 +01:00
return res.status(400).end(err.message);
}
2017-12-07 03:30:56 +01:00
});
app.listen(3002, function () {
2017-12-10 15:03:09 +01:00
console.log('Beebot app listening on port 3002!')
2017-12-07 03:30:56 +01:00
})
// Discord stuff
var client = new Discord.Client({
2017-12-10 15:03:09 +01:00
autoReconnect: true
2017-12-07 03:30:56 +01:00
});
// manage roles permission is required
const invitelink = 'https://discordapp.com/oauth2/authorize?client_id='
2017-12-10 15:03:09 +01:00
+ config.discord.client_id + '&scope=bot&permissions=0';
2017-12-07 03:30:56 +01:00
const authlink = 'https://discordapp.com/oauth2/authorize?client_id='
2017-12-10 15:03:09 +01:00
+ config.discord.client_id + '&scope=email';
console.log("Bot invite link: " + invitelink);
2017-12-07 03:30:56 +01:00
client.login(config.discord.token).catch(function (error) {
2017-12-10 15:03:09 +01:00
if (error) {
console.error("Couldn't login: ", error.toString());
2017-12-10 15:03:09 +01:00
}
2017-12-07 03:30:56 +01:00
});
function findEmoji(str) {
const discordEmote = /<:(\w+):(\d+)>/g.exec(str)
2017-12-10 15:03:09 +01:00
if (discordEmote) {
2017-12-07 03:30:56 +01:00
return {
name: discordEmote[1],
id: discordEmote[2],
url: `https://cdn.discordapp.com/emojis/${discordEmote[2]}.png`
}
}
let unicodeEmoji;
2017-12-10 15:03:09 +01:00
twemoji.parse(str, (name, emoji) => {
if (unicodeEmoji) return false;
2017-12-07 03:30:56 +01:00
unicodeEmoji = {
2017-12-10 15:03:09 +01:00
name,
2017-12-07 03:30:56 +01:00
id: name,
url: emoji.base + emoji.size + "/" + name + emoji.ext
}
return false;
});
return unicodeEmoji;
}
2017-12-10 15:56:37 +01:00
function loadImage(url) {
return new Promise((resolve, reject) => {
console.log("Getting " + url);
if (url) {
request.get({ url: url, encoding: null }, function (e, r, data) {
if (e) {
return reject({ status: (r && r.statusCode || 500), error: e });
}
var img = new Image();
img.src = data;
resolve(img);
})
}
});
}
2017-12-19 15:43:00 +01:00
function reverseString(str) {
return str.split("").reverse().join("");
}
const commands = Object.keys(templates).map(x => '/'+x).join(', ');
const otherCommands = {
"invite": `Invite link: <${invitelink}>`,
2017-12-19 15:47:28 +01:00
"help": `Available commands: ${commands}.\nUse \\\\<command> to flip the template horizontally.\nInvite link: <${invitelink}>`,
"beebot": `Available commands: ${commands}.\nUse \\\\<command> to flip the template horizontally.\nInvite link: <${invitelink}>`
2017-12-19 15:43:00 +01:00
}
2017-12-10 15:56:37 +01:00
client.on('message', async function (message) {
2017-12-12 03:08:13 +01:00
console.log(`[${message.guild.name} - ${message.channel.name}] ${message.author.username}#${message.author.discriminator}: ${message.cleanContent}`);
2017-12-10 15:56:37 +01:00
2017-12-19 15:43:00 +01:00
let commandParsed = /^([\/\\])(\w+)\b/.exec(message.cleanContent);
if(commandParsed) {
const [, direction, command] = commandParsed;
if(otherCommands[command]) {
const text = otherCommands[command];
message.channel.send(direction === "\\" ? reverseString(text) : text);
return;
}
2017-12-12 14:34:33 +01:00
}
2017-12-12 02:26:44 +01:00
2017-12-10 15:56:37 +01:00
const messageSplit = message.cleanContent.split(" ");
const emoji = findEmoji(message.cleanContent);
let result = null;
2017-12-10 23:42:10 +01:00
let count = 0;
2017-12-10 15:56:37 +01:00
try {
if (emoji) {
let name = emoji.name;
2017-12-10 23:42:10 +01:00
for (var i = 0; i < messageSplit.length && count < 4; ++i) {
2017-12-19 15:43:00 +01:00
commandParsed = /^([\/\\])(\w+)\b/.exec(messageSplit[i]);
if (commandParsed) {
const [, direction, command] = commandParsed;
console.log("Got command ",direction, command, direction === '\\' ? "flipped":"not flipped");
if(templates[command]) {
count++;
name += command;
if (result === null) result = await loadImage(emoji.url);
const templateData = templates[command];
all(templateData, template => {
result = render(template, result, null, direction === '\\');
})
}
2017-12-10 23:42:10 +01:00
} else {
if(i===0) return;
2017-12-10 15:56:37 +01:00
}
}
if (result) {
var messageOptions = {
files: [
{ attachment: result.toBuffer(), name: name + ".png" }
]
}
message.channel.send("", messageOptions);
2017-12-10 15:03:09 +01:00
}
2017-12-10 15:56:37 +01:00
}
} catch(err) {
console.error(err);
2017-12-10 15:03:09 +01:00
}
2017-12-07 03:30:56 +01:00
});