Compare commits
10 Commits
main
...
v3.4.4-dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 98827a372e | |||
| 28d0cc0446 | |||
| 14556a50c5 | |||
| 445fa4e9f4 | |||
| 80c23ca7db | |||
| 017eaddf9b | |||
| 23c81305a0 | |||
| 4c5e265d2e | |||
| 7df608e0e6 | |||
| 720366b04b |
46
April-Fools.md
Normal file
46
April-Fools.md
Normal file
@ -0,0 +1,46 @@
|
||||
# NodBot April Fools
|
||||
* At midnight EDT on April 1st, 2025, NodBot will send a message in `#announcements` alerting to users of the 'Hub that there has been an update to the Terms of Use and Privacy Policy of NodBot.
|
||||
* This message will also announce a new subscription-based model of the bot whereby users must pay $X/mo to continue using the bot.
|
||||
* NodBot will respond to all (?) commands from unauthorized users (freeloaders) with a denial message with a link to my PayPal where users can pay their monthly fees.
|
||||
* When a user is added to the authorized users list, NodBot should send a message somewhere in the 'Hub, mocking the user, maybe calling them a simp.
|
||||
* Obvious exemption for me for all of these rules.
|
||||
|
||||
# Message
|
||||
> 🚨 Attention, peasants 🚨
|
||||
>
|
||||
> Big changes are here! As of today, NodBot is no longer a free service. Due to rising operational costs, we’re moving to a subscription-based model.
|
||||
>
|
||||
> 💰 New Pricing Structure:
|
||||
>
|
||||
> * Basic Peasant Tier: $10/month
|
||||
> * Unlocks basic commands:
|
||||
> * `.gif`, `.pasta`, `.md`
|
||||
>
|
||||
> * Premium Sucker Tier: $15/month
|
||||
> * Grants access to NodBot’s premium commands:
|
||||
> * `.joint`, `/strain`
|
||||
>
|
||||
> * Ultimate Simp Tier: $20/month
|
||||
> * Grants access to exclusive managerial commands:
|
||||
> * `/setnick`, `/edit`, `/save`
|
||||
>
|
||||
> Effective immediately, non-paying users (freeloaders) will have all commands rejected. To regain access, kindly deposit your hard-earned cash via this link: [PayPal](https://paypal.me/v0idf1sh).
|
||||
>
|
||||
> Thank you for your continued (and now mandatory) support!
|
||||
>
|
||||
> — NodBot, your favorite paywalled AI overlord
|
||||
|
||||
### Terms of Use
|
||||
By continuing to exist within the same digital space as NodBot, you automatically agree to the following terms:
|
||||
* Subscription Fees – Access to NodBot is now a privilege, not a right. Users must pay the required fees or suffer the consequences (i.e., total rejection and public shaming).
|
||||
* Payment Processing Period – Due to fraud prevention measures, payments must be verified before access to the bot is restored. Please allow 2-4 hours for access to be restored.
|
||||
* Non-Refundable Payments – If you thought there were refunds, think again moron. No take-backs.
|
||||
* Service Interruptions – NodBot may go offline at any time due to totally legitimate server issues. No compensation will be provided.
|
||||
* Arbitrary Rule Enforcement – Rules are subject to change at my whim, and compliance is mandatory.
|
||||
|
||||
### Privacy Policy
|
||||
* Data Collection – NodBot does collect personal data, including but not limited to: location, IP address, MAC address, physical address, mother's maiden name, social security number, credit card numbers, phone fingerprints, physical fingerprints, penis size and girth, first pet's name, city where you met your spouse, and city where your parents met.
|
||||
* Payment Info – All payments are processed through a sketchy-looking PayPal link. NodBot and voidf1sh take no responsibility if your bank calls you afterward.
|
||||
* Chat Logs – NodBot may or may not remember every dumbass thing you’ve ever typed. Just assume it does.
|
||||
* Third-Party Sharing – Your usage data may be shared with savage's mom
|
||||
* Right to Be Forgotten – You can request NodBot forget your existence, but that requires a one-time processing fee of $50.
|
||||
@ -1,4 +1,7 @@
|
||||
## v3.4.x
|
||||
#### v3.4.4 (#30)
|
||||
* [WIP] Add Meme Generator
|
||||
|
||||
#### v3.4.3 (#29)
|
||||
* Fix `.gif` replies to redirect to the original replyee (#26)
|
||||
|
||||
|
||||
180
functions.js
180
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,173 @@ 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, labels, values) {
|
||||
const fieldOneLabel = labels ? labels[0] : 'Text Field:';
|
||||
const fieldOneValue = values ? values[0] : '';
|
||||
// Create the modal
|
||||
const modal = new Modal()
|
||||
.setCustomId('oneFieldMemeModal')
|
||||
.setTitle('Meme Generator');
|
||||
// Create the text input
|
||||
const textInput = new TextInputComponent()
|
||||
.setCustomId('memeTextField')
|
||||
.setLabel(fieldOneLabel)
|
||||
.setValue(fieldOneValue)
|
||||
.setStyle('SHORT');
|
||||
// Create and pre-fill a template ID field
|
||||
const templateIdField = new TextInputComponent()
|
||||
.setCustomId('memeTemplateId')
|
||||
.setLabel('Template ID: (advanced)')
|
||||
.setValue(templateId)
|
||||
.setStyle('SHORT');
|
||||
// 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, labels, values) {
|
||||
const fieldOneLabel = labels ? labels[0] : 'Text Field 1:';
|
||||
const fieldTwoLabel = labels ? labels[1] : 'Text Field 2:';
|
||||
const fieldOneValue = values ? values[0] : '';
|
||||
const fieldTwoValue = values ? values[1] : '';
|
||||
// Create the modal
|
||||
const modal = new Modal()
|
||||
.setCustomId('twoFieldMemeModal')
|
||||
.setTitle('Meme Generator');
|
||||
// Create the first text input
|
||||
const fieldOneTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldOne')
|
||||
.setLabel(fieldOneLabel)
|
||||
.setValue(fieldOneValue)
|
||||
.setStyle('SHORT');
|
||||
// Create the second text input
|
||||
const fieldTwoTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldTwo')
|
||||
.setLabel(fieldTwoLabel)
|
||||
.setValue(fieldTwoValue)
|
||||
.setStyle('SHORT');
|
||||
// Create and pre-fill a template ID field
|
||||
const templateIdField = new TextInputComponent()
|
||||
.setCustomId('memeTemplateId')
|
||||
.setLabel('Template ID: (advanced)')
|
||||
.setValue(templateId)
|
||||
.setStyle('SHORT');
|
||||
// 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, labels, values) {
|
||||
const fieldOneLabel = labels ? labels[0] : 'Text Field 1:';
|
||||
const fieldTwoLabel = labels ? labels[1] : 'Text Field 2:';
|
||||
const fieldThreeLabel = labels ? labels[2] : 'Text Field 3:';
|
||||
const fieldOneValue = values ? values[0] : '';
|
||||
const fieldTwoValue = values ? values[1] : '';
|
||||
const fieldThreeValue = values ? values[2] : '';
|
||||
// Create the modal
|
||||
const modal = new Modal()
|
||||
.setCustomId('threeFieldMemeModal')
|
||||
.setTitle('Meme Generator');
|
||||
// Create the first text input
|
||||
const fieldOneTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldOne')
|
||||
.setLabel(fieldOneLabel)
|
||||
.setValue(fieldOneValue)
|
||||
.setStyle('SHORT');
|
||||
// Create the second text input
|
||||
const fieldTwoTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldTwo')
|
||||
.setLabel(fieldTwoLabel)
|
||||
.setValue(fieldTwoValue)
|
||||
.setStyle('SHORT');
|
||||
// Create the third text input
|
||||
const fieldThreeTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldThree')
|
||||
.setLabel(fieldThreeLabel)
|
||||
.setValue(fieldThreeValue)
|
||||
.setStyle('SHORT');
|
||||
// Create and pre-fill a template ID field
|
||||
const templateIdField = new TextInputComponent()
|
||||
.setCustomId('memeTemplateId')
|
||||
.setLabel('Template ID: (advanced)')
|
||||
.setValue(templateId)
|
||||
.setStyle('SHORT');
|
||||
// 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, labels, values) {
|
||||
const fieldOneLabel = labels ? labels[0] : 'Text Field 1:';
|
||||
const fieldTwoLabel = labels ? labels[1] : 'Text Field 2:';
|
||||
const fieldThreeLabel = labels ? labels[2] : 'Text Field 3:';
|
||||
const fieldFourLabel = labels ? labels[3] : 'Text Field 4:';
|
||||
const fieldOneValue = values ? values[0] : '';
|
||||
const fieldTwoValue = values ? values[1] : '';
|
||||
const fieldThreeValue = values ? values[2] : '';
|
||||
const fieldFourValue = values ? values[3] : '';
|
||||
// Create the modal
|
||||
const modal = new Modal()
|
||||
.setCustomId('fourFieldMemeModal')
|
||||
.setTitle('Meme Generator');
|
||||
// Create the first text input
|
||||
const fieldOneTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldOne')
|
||||
.setLabel(fieldOneLabel)
|
||||
.setValue(fieldOneValue)
|
||||
.setStyle('SHORT');
|
||||
// Create the second text input
|
||||
const fieldTwoTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldTwo')
|
||||
.setLabel(fieldTwoLabel)
|
||||
.setValue(fieldTwoValue)
|
||||
.setStyle('SHORT');
|
||||
// Create the third text input
|
||||
const fieldThreeTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldThree')
|
||||
.setLabel(fieldThreeLabel)
|
||||
.setValue(fieldThreeValue)
|
||||
.setStyle('SHORT');
|
||||
// Create the fourth text input
|
||||
const fieldFourTextInput = new TextInputComponent()
|
||||
.setCustomId('memeTextFieldFour')
|
||||
.setLabel(fieldFourLabel)
|
||||
.setValue(fieldFourValue)
|
||||
.setStyle('SHORT');
|
||||
// Create and pre-fill a template ID field
|
||||
const templateIdField = new TextInputComponent()
|
||||
.setCustomId('memeTemplateId')
|
||||
.setLabel('Template ID: (advanced)')
|
||||
.setValue(templateId)
|
||||
.setStyle('SHORT');
|
||||
// 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) {
|
||||
@ -861,4 +1039,4 @@ const functions = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = functions;
|
||||
module.exports = functions;
|
||||
|
||||
45
main.js
45
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: 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: 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: 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: memeUrl });
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// dot-commands
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nodbot",
|
||||
"version": "3.4.3",
|
||||
"version": "3.4.4",
|
||||
"description": "Nods and Nod Accessories",
|
||||
"main": "main.js",
|
||||
"dependencies": {
|
||||
@ -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"
|
||||
|
||||
89
slash-commands/meme.js
Normal file
89
slash-commands/meme.js
Normal file
@ -0,0 +1,89 @@
|
||||
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||
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' },
|
||||
{ name: 'Bell Curve', value: '533936279' },
|
||||
)),
|
||||
async execute(interaction) {
|
||||
try {
|
||||
const template = interaction.options.getString('template');
|
||||
let memeModal;
|
||||
// Switch the template
|
||||
switch (template) {
|
||||
// One-Field Memes
|
||||
// Two-Field Memes
|
||||
// Drake Hotline Bling
|
||||
case '181913649':
|
||||
// Generate a modal with two text inputs
|
||||
memeModal = fn.memes.twoFieldModal(template, ['Drake No', 'Drake Yes']);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// Y'all Got Any More...
|
||||
case '124055727':
|
||||
// Generate a modal with two text inputs
|
||||
memeModal = fn.memes.twoFieldModal(template, ['Top', 'Bottom Text'], ['Y\'all got any more of ', '']);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// Uno Draw 25
|
||||
case '217743513':
|
||||
// Generate a modal with two text inputs
|
||||
memeModal = fn.memes.twoFieldModal(template, ['<blank> or draw 25', 'Caption Above Person'], ['', 'Me']);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// Three-Field Memes
|
||||
// Bell Curve
|
||||
case '533936279':
|
||||
// Generate a modal with two text inputs
|
||||
memeModal = fn.memes.threeFieldModal(template, ['Left', 'Middle', 'Right']);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// Anakin & Padme
|
||||
case '322841258':
|
||||
// Generate a modal with three text inputs
|
||||
memeModal = fn.memes.threeFieldModal(template, ['Anakin', 'Padme', 'Padme'], ['', '', 'Right?']);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// We are not the same
|
||||
case '342785297':
|
||||
// Generate a modal with three text inputs
|
||||
memeModal = fn.memes.threeFieldModal(template, ['You...', 'I...', 'We...'], ['', '', 'We are not the same.']);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// Surprised Pikachu
|
||||
case '155067746':
|
||||
memeModal = fn.memes.threeFieldModal(template);
|
||||
await interaction.showModal(memeModal);
|
||||
break;
|
||||
// Two Buttons
|
||||
case '87743020':
|
||||
// Generate a modal with three text inputs
|
||||
memeModal = fn.memes.threeFieldModal(template, ['Button 1', 'Button 2', 'Person Caption']);
|
||||
await interaction.showModal(memeModal);
|
||||
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!');
|
||||
}
|
||||
},
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user