amyjr/src/commands/caption.ts

107 linhas
Sem EOL
3,8 KiB
TypeScript

import {
ActionRowBuilder,
ApplicationCommandType, AttachmentBuilder,
ContextMenuCommandBuilder,
ContextMenuCommandInteraction,
Message,
MessageFlags,
type ModalActionRowComponentBuilder,
ModalBuilder,
type ModalSubmitInteraction,
TextInputBuilder,
TextInputStyle
} from "discord.js";
import { AmyodalBuilder, ContextyalBuilder } from "../util.ts";
import { NO_EXTRA_CONFIG, type Config } from "../config.ts";
const imagecache: Record<string, string> = {};
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import { hash } from "crypto"
import { createCanvas, loadImage, registerFont } from "canvas";
import path from "node:path";
import { fileURLToPath } from "url";
import { declareCommand } from "../command.ts";
export default declareCommand({
targetType: ApplicationCommandType.Message,
contextDefinition:
new ContextMenuCommandBuilder()
.setName('caption')
.setType(ApplicationCommandType.Message),
async run(interaction: ContextMenuCommandInteraction, target: Message): Promise<void> {
let attachment = target.attachments.first();
if (!attachment) {
await interaction.reply({
content: "no attachments found",
flags: [MessageFlags.Ephemeral]
});
return;
}
const hashed = hash("md5", attachment.url);
imagecache[hashed] = attachment.url
await interaction.showModal(new ContextyalBuilder(this.commandName)
.setCustomId(hashed)
.setTitle('what do you want the meme to be')
.addComponents(
new ActionRowBuilder<ModalActionRowComponentBuilder>()
.addComponents(
new TextInputBuilder()
.setCustomId('pawSize')
.setLabel("whats the meme?")
.setStyle(TextInputStyle.Short)
.setPlaceholder("haha funny")
)
))
},
async modal(interaction: ModalSubmitInteraction, config: Config) {
//putting this here is a bad idea
registerFont(path.join(__dirname, '../../impact.ttf'), { family: 'impact' });
await interaction.deferReply()
const memetext = interaction.fields.fields.get("pawSize")?.value;
if (!memetext) {
console.error("exit quietly and cry")
return;
}
const imageUrl = imagecache[interaction.customId.replaceAll("CC:caption|", "")]
const image = await loadImage(imageUrl);
const width = image.width;
const height = Math.max(image.height * 1.2, image.width / 2)
const heightDiff = height - image.height
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
ctx.fillStyle = "white"
ctx.fillRect(0, 0, width, height)
ctx.drawImage(image, 0, heightDiff);
ctx.fillStyle = "black"
let fontSize = width / 6;
ctx.font = `${fontSize}px impact`;
ctx.textAlign = "center"
let metrics = ctx.measureText(memetext);
while ((metrics.width > width * 0.8 || metrics.actualBoundingBoxAscent > height * 0.2) && fontSize > 1) {
fontSize--;
ctx.font = `${fontSize}px impact`;
metrics = ctx.measureText(memetext);
}
const yPos = heightDiff / 2 + metrics.actualBoundingBoxAscent / 2;
ctx.fillText(memetext, width / 2, yPos);
const buffer = canvas.toBuffer('image/png');
await interaction.followUp({
files: [
new AttachmentBuilder(buffer)
.setName('meme.png')
.setDescription(`some meme`),
],
})
},
dependsOn: NO_EXTRA_CONFIG,
commandName: "caption",
})