From 7df608e0e677998aa8845098145675aee36fe83c Mon Sep 17 00:00:00 2001 From: Skylar Grant Date: Sun, 9 Feb 2025 19:43:06 -0500 Subject: [PATCH] MVP for meme generation --- functions.js | 148 +++++++++++++++++++++++++++++++++++++++++ main.js | 45 +++++++++++++ package.json | 1 + slash-commands/meme.js | 62 +++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100644 slash-commands/meme.js diff --git a/functions.js b/functions.js index fc3f73b..188b312 100644 --- a/functions.js +++ b/functions.js @@ -16,6 +16,7 @@ const zlib = require('zlib'); // Discord.js const Discord = require('discord.js'); +const { MessageActionRow, Modal, TextInputComponent } = require('discord.js'); // Fuzzy text matching for db lookups const FuzzySearch = require('fuzzy-search'); @@ -23,6 +24,16 @@ const FuzzySearch = require('fuzzy-search'); // Axios for APIs const axios = require('axios'); +// Imgflip API +let imgflip; +(async () => { + const Imgflip = (await import('imgflip')).default; + imgflip = new Imgflip({ + username: process.env.imgflipUser, + password: process.env.imgflipPass, + }); +})(); + // Various imports from other files const config = require('./config.json'); const strings = require('./strings.json'); @@ -616,6 +627,143 @@ const functions = { return pastaSearcher.search(query).slice(0,25); } }, + memes: { + generate(templateId, panelData) { + return new Promise((resolve, reject) => { + imgflip.meme(templateId, { + captions: panelData + }).then((res) => { + resolve(res); + }).catch((err) => { + reject(err); + }); + }); + }, + oneFieldModal(templateId) { + // Create the modal + const modal = new Modal() + .setCustomId('oneFieldMemeModal') + .setTitle('Meme Generator'); + // Create the text input + const textInput = new TextInputComponent() + .setCustomId('memeTextField') + .setLabel('Text Field:') + .setStyle('SHORT'); + // Create and pre-fill a template ID field + const templateIdField = new TextInputComponent() + .setCustomId('memeTemplateId') + .setLabel('Template ID: (advanced)') + .setStyle('SHORT') + .setValue(templateId); + // Add the components to the modal + const textRow = new MessageActionRow().addComponents(textInput); + const templateIdRow = new MessageActionRow().addComponents(templateIdField); + modal.addComponents(textRow, templateIdRow); + return modal; + }, + twoFieldModal(templateId) { + // Create the modal + const modal = new Modal() + .setCustomId('twoFieldMemeModal') + .setTitle('Meme Generator'); + // Create the first text input + const fieldOneTextInput = new TextInputComponent() + .setCustomId('memeTextFieldOne') + .setLabel('Text Field 1:') + .setStyle('SHORT'); + // Create the second text input + const fieldTwoTextInput = new TextInputComponent() + .setCustomId('memeTextFieldTwo') + .setLabel('Text Field 2:') + .setStyle('SHORT'); + // Create and pre-fill a template ID field + const templateIdField = new TextInputComponent() + .setCustomId('memeTemplateId') + .setLabel('Template ID: (advanced)') + .setStyle('SHORT') + .setValue(templateId); + // Add the components to the modal + const fieldOneRow = new MessageActionRow().addComponents(fieldOneTextInput); + const fieldTwoRow = new MessageActionRow().addComponents(fieldTwoTextInput); + const templateIdRow = new MessageActionRow().addComponents(templateIdField); + modal.addComponents(fieldOneRow, fieldTwoRow, templateIdRow); + return modal; + }, + threeFieldModal(templateId) { + // Create the modal + const modal = new Modal() + .setCustomId('threeFieldMemeModal') + .setTitle('Meme Generator'); + // Create the first text input + const fieldOneTextInput = new TextInputComponent() + .setCustomId('memeTextFieldOne') + .setLabel('Text Field 1:') + .setStyle('SHORT'); + // Create the second text input + const fieldTwoTextInput = new TextInputComponent() + .setCustomId('memeTextFieldTwo') + .setLabel('Text Field 2:') + .setStyle('SHORT'); + // Create the third text input + const fieldThreeTextInput = new TextInputComponent() + .setCustomId('memeTextFieldThree') + .setLabel('Text Field 3:') + .setStyle('SHORT'); + // Create and pre-fill a template ID field + const templateIdField = new TextInputComponent() + .setCustomId('memeTemplateId') + .setLabel('Template ID: (advanced)') + .setStyle('SHORT') + .setValue(templateId); + // Add the components to the modal + const fieldOneRow = new MessageActionRow().addComponents(fieldOneTextInput); + const fieldTwoRow = new MessageActionRow().addComponents(fieldTwoTextInput); + const fieldThreeRow = new MessageActionRow().addComponents(fieldThreeTextInput); + const templateIdRow = new MessageActionRow().addComponents(templateIdField); + modal.addComponents(fieldOneRow, fieldTwoRow, fieldThreeRow, templateIdRow); + return modal; + }, + fourFieldModal(templateId) { + // Create the modal + const modal = new Modal() + .setCustomId('fourFieldMemeModal') + .setTitle('Meme Generator'); + // Create the first text input + const fieldOneTextInput = new TextInputComponent() + .setCustomId('memeTextFieldOne') + .setLabel('Text Field 1:') + .setStyle('SHORT'); + // Create the second text input + const fieldTwoTextInput = new TextInputComponent() + .setCustomId('memeTextFieldTwo') + .setLabel('Text Field 2:') + .setStyle('SHORT'); + // Create the third text input + const fieldThreeTextInput = new TextInputComponent() + .setCustomId('memeTextFieldThree') + .setLabel('Text Field 3:') + .setStyle('SHORT'); + // Create the fourth text input + const fieldFourTextInput = new TextInputComponent() + .setCustomId('memeTextFieldFour') + .setLabel('Text Field 4:') + .setStyle('SHORT'); + // Create and pre-fill a template ID field + const templateIdField = new TextInputComponent() + .setCustomId('memeTemplateId') + .setLabel('Template ID: (advanced)') + .setStyle('SHORT') + .setValue(templateId); + // Add the components to the modal + const fieldOneRow = new MessageActionRow().addComponents(fieldOneTextInput); + const fieldTwoRow = new MessageActionRow().addComponents(fieldTwoTextInput); + const fieldThreeRow = new MessageActionRow().addComponents(fieldThreeTextInput); + const fieldFourRow = new MessageActionRow().addComponents(fieldFourTextInput); + const templateIdRow = new MessageActionRow().addComponents(templateIdField); + modal.addComponents(fieldOneRow, fieldTwoRow, fieldThreeRow, fieldFourRow, templateIdRow); + return modal; + }, + }, // Parent-Level functions (miscellaneuous) closeRequest(requestId, interaction) { if (interaction.user.id == ownerId) { diff --git a/main.js b/main.js index 42f29ce..f595c1a 100644 --- a/main.js +++ b/main.js @@ -57,6 +57,7 @@ client.once('ready', async () => { // slash-commands client.on('interactionCreate', async interaction => { + if (isDev) console.log('Interaction Type: ' + interaction.type); if (interaction.isCommand()) { if (isDev) { console.log('Interaction ID: ' + interaction.id); @@ -118,6 +119,50 @@ client.on('interactionCreate', async interaction => { break; } } + + if (interaction.isModalSubmit()) { + if (isDev) console.log('Modal Submit ID: ' + interaction.id); + const template = interaction.fields.getTextInputValue('memeTemplateId'); + let memeTextFieldOne, memeTextFieldTwo, memeTextFieldThree, memeTextFieldFour, memeUrl; + switch (interaction.customId) { + case 'oneFieldMemeModal': + memeTextFieldOne = interaction.fields.getTextInputValue('memeTextFieldOne'); + console.log(`Text: ${memeTextFieldOne}`); + memeUrl = await fn.memes.generate(template, [memeTextFieldOne]); + console.log(memeUrl); + await interaction.reply({ content: 'Here is your meme: ' + memeUrl }); + break; + case 'twoFieldMemeModal': + memeTextFieldOne = interaction.fields.getTextInputValue('memeTextFieldOne'); + memeTextFieldTwo = interaction.fields.getTextInputValue('memeTextFieldTwo'); + console.log(`Text: ${memeTextFieldOne}, ${memeTextFieldTwo}`); + memeUrl = await fn.memes.generate(template, [memeTextFieldOne, memeTextFieldTwo]); + console.log(memeUrl); + await interaction.reply({ content: 'Here is your meme: ' + memeUrl }); + break; + case 'threeFieldMemeModal': + memeTextFieldOne = interaction.fields.getTextInputValue('memeTextFieldOne'); + memeTextFieldTwo = interaction.fields.getTextInputValue('memeTextFieldTwo'); + memeTextFieldThree = interaction.fields.getTextInputValue('memeTextFieldThree'); + console.log(`Text: ${memeTextFieldOne}, ${memeTextFieldTwo}, ${memeTextFieldThree}`); + memeUrl = await fn.memes.generate(template, [memeTextFieldOne, memeTextFieldTwo, memeTextFieldThree]); + console.log(memeUrl); + await interaction.reply({ content: 'Here is your meme: ' + memeUrl }); + break; + case 'fourFieldMemeModal': + memeTextFieldOne = interaction.fields.getTextInputValue('memeTextFieldOne'); + memeTextFieldTwo = interaction.fields.getTextInputValue('memeTextFieldTwo'); + memeTextFieldThree = interaction.fields.getTextInputValue('memeTextFieldThree'); + memeTextFieldFour = interaction.fields.getTextInputValue('memeTextFieldFour'); + console.log(`Text: ${memeTextFieldOne}, ${memeTextFieldTwo}, ${memeTextFieldThree}, ${memeTextFieldFour}`); + memeUrl = await fn.memes.generate(template, [memeTextFieldOne, memeTextFieldTwo, memeTextFieldThree, memeTextFieldFour]); + console.log(memeUrl); + await interaction.reply({ content: 'Here is your meme: ' + memeUrl }); + break; + default: + break; + } + } }); // dot-commands diff --git a/package.json b/package.json index b152983..93a5959 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "discord.js": "^13.15.1", "dotenv": "^10.0.0", "fuzzy-search": "^3.2.1", + "imgflip": "^4.0.0", "mysql": "^2.18.1", "openai": "^4.12.0", "tenorjs": "^1.0.10" diff --git a/slash-commands/meme.js b/slash-commands/meme.js new file mode 100644 index 0000000..a15122e --- /dev/null +++ b/slash-commands/meme.js @@ -0,0 +1,62 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); +const { MessageActionRow, Modal, TextInputComponent } = require('discord.js'); +const fn = require('../functions.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('meme') + .setDescription('Generate a meme from a template') + .addStringOption(option => + option.setName('template') + .setDescription('The meme template') + .setRequired(true) + .addChoices( + { name: 'Drake Hotline Bling', value: '181913649' }, + { name: 'Anakin & Padme', value: '322841258' }, + { name: 'Y\'all Got Any More...', value: '124055727' }, + { name: 'We Are Not The Same', value: '342785297' }, + { name: 'Surprised Pikachu', value: '155067746' }, + { name: 'Two Buttons', value: '87743020' }, + { name: 'Uno Draw 25', value: '217743513' } + ) + ), + async execute(interaction) { + try { + const template = interaction.options.getString('template'); + + // Switch the template + switch (template) { + // One-Field Memes + case '342785297': // We are not the same + // Generate a modal with one text input + const oneFieldMemeModal = fn.memes.oneFieldModal(template); + await interaction.showModal(oneFieldMemeModal); + break; + // Two-Field Memes + case '181913649': // Y'all got any more of that + case '124055727': // Drake Hotline Bling No/Yes + case '217743513': // Uno Draw 25 + // Generate a modal with two text inputs + const twoFieldMemeModal = fn.memes.twoFieldModal(template); + await interaction.showModal(twoFieldMemeModal); + break; + // Three-Field Memes + case '322841258': // Anakin & Padme + case '342785297': // We are not the same + case '155067746': // Surprised Pikachu + case '87743020': // Two Buttons + // Generate a modal with three text inputs + const threeFieldMemeModal = fn.memes.threeFieldModal(template); + await interaction.showModal(threeFieldMemeModal); + break; + default: + await interaction.reply('Invalid meme template'); + break; + } + + } catch (error) { + console.error(error); + await interaction.reply('There was an error while executing this command!'); + } + }, +}; \ No newline at end of file