v3 to Prod
This commit is contained in:
parent
5c8ea22626
commit
c6045361d0
22
.github/workflows/deploy.yaml
vendored
Normal file
22
.github/workflows/deploy.yaml
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: Node.js CI/CD
|
||||||
|
|
||||||
|
on: [push] # tells github to run this on any push to the repository
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref == 'refs/heads/main' # we tell Github to only execute this step if we're on our master branch (so we don't put unfinished branches in production)
|
||||||
|
steps:
|
||||||
|
- name: Deploying to Ayrenn
|
||||||
|
uses: appleboy/ssh-action@master # An action made to control Linux servers
|
||||||
|
with: # We set all our secrets here for the action, these won't be shown in the action logs
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
script: |
|
||||||
|
cd nodbot-v3 # we move into our app's folder
|
||||||
|
git pull # we pull any changes from git
|
||||||
|
npm prune # we remove any unused dependencies
|
||||||
|
npm install # we install any missing dependencies
|
||||||
|
pm2 reload all # we reload the app via PM2
|
38
README.md
38
README.md
@ -1,38 +0,0 @@
|
|||||||
# NodBot
|
|
||||||
A simple Discord bot created by @voidf1sh#0420 for retreiving gifs, saving copypastas, and more coming soon.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
NodBot depends on `fs`, `discord.js`, `dotenv`, `tenorjs`, `pg`, and `axios`.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
Dynamic Help Message
|
|
||||||
Ability to save favorite gifs and copypastas
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
All commands are provided as "file extensions" instead of prefixes to the message.
|
|
||||||
|
|
||||||
```
|
|
||||||
foo.gif -- Will return the first GIF for 'foo'
|
|
||||||
foo.savegif -- Will send the first GIF result for 'foo', with Reactions to browse the results and save the GIF
|
|
||||||
foo.savepasta -- Prompts the user for the copypasta text to save as 'foo.pasta'
|
|
||||||
foo.pasta -- If a copypasta by the name of 'foo' is saved, the bot will send it
|
|
||||||
foo.weather -- Returns the current weather in 'foo', where 'foo' is a city or ZIP code
|
|
||||||
foobar.spongebob - Returns 'FoObAr' aka SpongeBob text
|
|
||||||
.joint -- Puff, Puff, Pass.
|
|
||||||
```
|
|
||||||
|
|
||||||
## To Do
|
|
||||||
v3 TODO:
|
|
||||||
Create database for storage of gifs, pastas, joint phrases, etc.
|
|
||||||
Migrate to Discord.js v13 Beta
|
|
||||||
Implement Replies to messages
|
|
||||||
Implement buttons in lieu of Reacts
|
|
||||||
|
|
||||||
DONE: Clean up text input for copypastas, line breaks and apostrophes break the bot.
|
|
||||||
Add ability to reload commands, gifs, pastas, etc without rebooting the bot manually.
|
|
||||||
DONE: Change `savepasta` to use a collector and ask for the name or the pasta.
|
|
||||||
Add Stock quotes from Yahoo Finance API
|
|
||||||
Add self-delete if wrongbad'd
|
|
||||||
Move most string literals to config.json or strings.json for ease of editing.
|
|
||||||
Make construction of the `data` element easier for the createEmbeds functions.
|
|
||||||
Find a Cannabis API for strain information lookup.
|
|
@ -1,20 +0,0 @@
|
|||||||
# Release Notes
|
|
||||||
|
|
||||||
## v2.2.1 Hotfix
|
|
||||||
Fix bug where saved content isn't saved as lowercase, making in unaccessible.
|
|
||||||
|
|
||||||
## v2.2.0
|
|
||||||
NodBot no longer stores saved GIFs, Copypastas, and other custom content locally. This means no more discrepancies between versions of the bot!
|
|
||||||
|
|
||||||
## v2.1.0
|
|
||||||
Want to add a phrase to the `.joint` rotation? Try `<phrase>.roll`.
|
|
||||||
|
|
||||||
Wondering what GIFs and Copypastas have been saved? Try `.gifs` and `.pastas`, also check out the new help message with `.help`!
|
|
||||||
|
|
||||||
NodBot now uses Tenor instead of Giphy for GIF searches!
|
|
||||||
|
|
||||||
Changing the method to search for and save GIFs for later reuse. Previously the bot simply sent a message containing the link to a GIF which Discord would display in the chat. However the new code uses Embeds to make the messages look prettier. These Embeds require a *direct* link to the GIF, which isn't very user friendly. Now you can search for a GIF and NodBot will DM you with results for you to browse before choosing the GIF you'd like to save, then name it.
|
|
||||||
|
|
||||||
Generic bug squashing, sanitizing of inputs, setting up some configs for deployment on Heroku.
|
|
||||||
|
|
||||||
Updating Copypasta save method to be interactive and give a less complicated command syntax.
|
|
29
TODO.md
Normal file
29
TODO.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[ v3.0.0 ]
|
||||||
|
*= Finish MySQL Migration
|
||||||
|
* = Import strain names to a collection
|
||||||
|
* = Implement fuzzy-search for strain lookup
|
||||||
|
* = Then pass confirmed-good strainName to fn.download.strain()
|
||||||
|
*= Test all functions
|
||||||
|
* = Write out the process used to test functionality to standardize it.
|
||||||
|
= Sanitize inputs
|
||||||
|
= Don't forget to test apostrophes and newlines.
|
||||||
|
= Emoji break strain lookup
|
||||||
|
= Find a way to filter out URLs that may have .extensions at the end
|
||||||
|
= Mentions in .strain crash
|
||||||
|
= Fix newline escaping in savepasta
|
||||||
|
= Check what inputs need to be sanitized
|
||||||
|
! Name checking for saving content !
|
||||||
|
|
||||||
|
[ v3.1.0 ]
|
||||||
|
= .jpg, .wav
|
||||||
|
= Audio/Video attachments for saved content.
|
||||||
|
= Pass The Joint
|
||||||
|
= Voting system for Super Adventure Club
|
||||||
|
|
||||||
|
|
||||||
|
[ v4.0.0 ]
|
||||||
|
= Scalability: modify the code to allow the bot to be used in multiple servers
|
||||||
|
= including saved content, saved commands, preferences, etc.
|
||||||
|
|
||||||
|
[ v?.?.? ]
|
||||||
|
= Joke generator for Hallihan
|
39
_deploy-commands.js
Normal file
39
_deploy-commands.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// dotenv for handling environment variables
|
||||||
|
const dotenv = require('dotenv');
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
const { REST } = require('@discordjs/rest');
|
||||||
|
const { Routes } = require('discord-api-types/v9');
|
||||||
|
const { guildId, clientId } = require('./config.json');
|
||||||
|
const token = process.env.TOKEN;
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const commands = [];
|
||||||
|
const commandFiles = fs.readdirSync('./slash-commands').filter(file => file.endsWith('.js'));
|
||||||
|
|
||||||
|
for (const file of commandFiles) {
|
||||||
|
const command = require(`./slash-commands/${file}`);
|
||||||
|
if (command.data != undefined) {
|
||||||
|
commands.push(command.data.toJSON());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(commands);
|
||||||
|
|
||||||
|
const rest = new REST({ version: '9' }).setToken(token);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
console.log('Started refreshing application (/) commands.');
|
||||||
|
|
||||||
|
await rest.put(
|
||||||
|
Routes.applicationGuildCommands(clientId, guildId),
|
||||||
|
{ body: commands },
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('Successfully reloaded application (/) commands.');
|
||||||
|
process.exit();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
})();
|
@ -1,27 +0,0 @@
|
|||||||
const axios = require("axios").default;
|
|
||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
method: 'GET',
|
|
||||||
url: 'https://forteweb-airportguide-airport-basic-info-v1.p.rapidapi.com/get_airport_by_iata',
|
|
||||||
params: {auth: 'authairport567', airport_id: 'LAX'},
|
|
||||||
headers: {
|
|
||||||
'x-rapidapi-key': '0b3f85bcb7msh1e6e80e963c9914p1d1934jsnc3542fc83520',
|
|
||||||
'x-rapidapi-host': 'forteweb-airportguide-airport-basic-info-v1.p.rapidapi.com'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'airport',
|
|
||||||
description: 'Get airport information by IATA code.',
|
|
||||||
usage: '<IATA>',
|
|
||||||
execute(message, file) {
|
|
||||||
options.params.airport_id = file.name;
|
|
||||||
axios.request(options).then(function (response) {
|
|
||||||
const embed = functions.createAirportEmbed(response.data, message.author, `${file.name}.${file.extension}`);
|
|
||||||
message.channel.send(embed).then().catch(err => console.error(err));
|
|
||||||
}).catch(function (error) {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
const fn = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'closereq',
|
|
||||||
description: 'Close a given request by ID',
|
|
||||||
usage: '<request_id>',
|
|
||||||
execute(message, file) {
|
|
||||||
fn.closeRequest(file.name);
|
|
||||||
message.channel.send(fn.textEmbed('Request closed.', message.author, file.extension));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
const functions = require('../functions');
|
|
||||||
const tenor = require('tenorjs').client({
|
|
||||||
"Key": process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration
|
|
||||||
"Filter": "off", // "off", "low", "medium", "high", not case sensitive
|
|
||||||
"Locale": "en_US", // Your locale here, case-sensitivity depends on input
|
|
||||||
"MediaFilter": "minimal", // either minimal or basic, not case sensitive
|
|
||||||
"DateFormat": "D/MM/YYYY - H:mm:ss A" // Change this accordingly
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'gif',
|
|
||||||
description: 'Send a GIF',
|
|
||||||
usage: '<GIF name or Search Query>',
|
|
||||||
execute(message, file) {
|
|
||||||
const client = message.client;
|
|
||||||
if (!client.gifs.has(file.name)) {
|
|
||||||
tenor.Search.Query(file.name, 1).then(res => {
|
|
||||||
if (res[0] == undefined) {
|
|
||||||
message.reply('Sorry I was unable to find a GIF of ' + file.name);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
const gifInfo = {
|
|
||||||
'name': file.name,
|
|
||||||
'embed_url': res[0].media[0].gif.url
|
|
||||||
};
|
|
||||||
message.channel.send(functions.createGifEmbed(gifInfo, message.author, `${file.name}.${file.extension} - Tenor`));
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
} else {
|
|
||||||
// message.channel.send(file.name + ' requested by ' + message.author.username + '\n' + client.gifs.get(file.name).embed_url);
|
|
||||||
const gifInfo = {
|
|
||||||
'name': file.name,
|
|
||||||
'embed_url': client.gifs.get(file.name).embed_url
|
|
||||||
};
|
|
||||||
message.channel.send(functions.createGifEmbed(gifInfo, message.author, `${file.name}.${file.extension} - Saved`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'gifs',
|
|
||||||
description: 'Get a list of saved GIFs',
|
|
||||||
execute(message, file) {
|
|
||||||
message.author.createDM().then(channel => {
|
|
||||||
channel.send(functions.createGIFList(message));
|
|
||||||
message.reply('I\'ve sent you a DM with a list of saved GIFs.')
|
|
||||||
}).catch(err => message.channel.send('Sorry I was unable to send you a DM.'));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'help',
|
|
||||||
description: 'Shows the help page.',
|
|
||||||
execute(message, file) {
|
|
||||||
message.author.createDM()
|
|
||||||
.then(dmChannel => {
|
|
||||||
dmChannel.send(functions.createHelpEmbed(message)).then().catch(err => console.error(err));
|
|
||||||
message.reply('I\'ve DM\'d you a copy of my help message!');
|
|
||||||
}).catch(err => console.error(err));
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,14 +0,0 @@
|
|||||||
const { emoji } = require('../src/strings.json');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'joint',
|
|
||||||
description: 'Pass the joint!',
|
|
||||||
execute(message, args) {
|
|
||||||
let phrases = [];
|
|
||||||
for (const entry of message.client.potphrases.map(potphrase => potphrase.content)) {
|
|
||||||
phrases.push(entry);
|
|
||||||
}
|
|
||||||
const randIndex = Math.floor(Math.random() * phrases.length);
|
|
||||||
message.channel.send(`${phrases[randIndex]} ${emoji.joint}`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: 'joints',
|
|
||||||
description: 'Get a list of the phrases saved for .joint',
|
|
||||||
execute(message, file) {
|
|
||||||
let phrases = [];
|
|
||||||
|
|
||||||
for (const phrase of message.client.potphrases.map(potphrase => potphrase.content)) {
|
|
||||||
phrases.push(phrase);
|
|
||||||
}
|
|
||||||
message.channel.send('Here are all the `.joint` phrases I have saved:\n\n' + phrases.join('\n'));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
const ownerID = process.env.ownerID;
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'kill',
|
|
||||||
description: 'Kills the bot OWNER ONLY',
|
|
||||||
execute(message, args) {
|
|
||||||
if (message.author.id == ownerID) {
|
|
||||||
message.channel.send('Shutting down the bot...')
|
|
||||||
.then(() => {
|
|
||||||
message.client.destroy();
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.reply('Sorry, only the owner can do that.');
|
|
||||||
message.client.users.fetch(ownerID)
|
|
||||||
.then(user => {
|
|
||||||
user.send(message.author.username + ' attempted to shutdown the bot.')
|
|
||||||
.then()
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'pasta',
|
|
||||||
description: 'Send a copypasta.',
|
|
||||||
usage: '<Copypasta Name>',
|
|
||||||
execute(message, file) {
|
|
||||||
const client = message.client;
|
|
||||||
const replyHeader = `\'${file.name}\' requested by: ${message.author.username}\n`;
|
|
||||||
let replyBody = '';
|
|
||||||
let iconUrl;
|
|
||||||
if (!client.pastas.has(file.name)) {
|
|
||||||
replyBody = 'Sorry I couldn\'t find that pasta.';
|
|
||||||
} else {
|
|
||||||
replyBody = client.pastas.get(file.name).content;
|
|
||||||
iconUrl = client.pastas.get(file.name).iconUrl;
|
|
||||||
}
|
|
||||||
message.channel.send(functions.pastaEmbed(replyBody, iconUrl, message.author));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'pastas',
|
|
||||||
description: 'Get a list of saved copypastas',
|
|
||||||
execute(message, file) {
|
|
||||||
message.author.createDM().then(channel => {
|
|
||||||
channel.send(functions.createPastaList(message));
|
|
||||||
message.channel.send('I\'ve sent you a DM with a list of saved copypastas.')
|
|
||||||
}).catch(err => message.channel.send('Sorry I was unable to send you a DM.'));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: 'ping',
|
|
||||||
description: 'Pong!',
|
|
||||||
execute(message, args) {
|
|
||||||
message.channel.send('Pong!');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
const fn = require('../functions');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'reload',
|
|
||||||
description: 'Reload saved GIFs, Pastas, Joint Phrases, etc',
|
|
||||||
execute(message, file) {
|
|
||||||
fn.reload(message.client);
|
|
||||||
message.reply('Reload Successful');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
const fn = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'request',
|
|
||||||
description: 'Submit a request to the bot developer.',
|
|
||||||
usage: '<request or feedback>',
|
|
||||||
execute(message, file) {
|
|
||||||
const request = file.name;
|
|
||||||
message.channel.send(fn.textEmbed('Your request has been submitted!\nRequest: ' + request, message.author, file.extension));
|
|
||||||
message.client.users.fetch(process.env.ownerID).then(user => {user.send(fn.textEmbed(request, message.author, file.extension));}).catch(error => { console.error(error);} );
|
|
||||||
fn.uploadRequest(message.author, file.name);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
const fn = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'requests',
|
|
||||||
description: 'Get a list of the currently active requests.',
|
|
||||||
execute(message, file) {
|
|
||||||
fn.getActiveRequests(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'roll',
|
|
||||||
description: 'Add a phrase to the .joint command',
|
|
||||||
usage: '<phrase to save>',
|
|
||||||
execute(message, file) {
|
|
||||||
functions.uploadPotPhrase(file.name);
|
|
||||||
message.channel.send('"' + file.name + '" has been added to the list');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
const tenor = require('tenorjs').client({
|
|
||||||
"Key": process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration
|
|
||||||
"Filter": "off", // "off", "low", "medium", "high", not case sensitive
|
|
||||||
"Locale": "en_US", // Your locale here, case-sensitivity depends on input
|
|
||||||
"MediaFilter": "minimal", // either minimal or basic, not case sensitive
|
|
||||||
"DateFormat": "D/MM/YYYY - H:mm:ss A" // Change this accordingly
|
|
||||||
});
|
|
||||||
const functions = require('../functions');
|
|
||||||
const { emoji } = require('../src/strings.json');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'savegif',
|
|
||||||
description: 'Saves a gif selected from a search to a given filename.',
|
|
||||||
usage: '<search query>',
|
|
||||||
execute(message, file) {
|
|
||||||
const query = file.name;
|
|
||||||
message.author.createDM().then(channel => {
|
|
||||||
tenor.Search.Query(query, 20)
|
|
||||||
.then(res => {
|
|
||||||
if (res[0] == undefined) {
|
|
||||||
channel.send('Sorry, I wasn\'t able to find a GIF of ' + file.name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let i = 0;
|
|
||||||
const data = {
|
|
||||||
"name": file.name,
|
|
||||||
"embed_url": res[0].media[0].gif.url,
|
|
||||||
"author": message.author
|
|
||||||
};
|
|
||||||
let embed = functions.createGifEmbed(data, message.author, `${Object.values(file).join('.')}`);
|
|
||||||
|
|
||||||
// Send the first GIF result as an Embed
|
|
||||||
channel.send(embed)
|
|
||||||
.then(selfMessage => {
|
|
||||||
// Add reactions to go back, forward, cancel and confirm GIF choice.
|
|
||||||
// React order is important so these are done in a chain
|
|
||||||
selfMessage.react(emoji.previous).then(() => {
|
|
||||||
selfMessage.react(emoji.confirm).then(() => {
|
|
||||||
selfMessage.react(emoji.next).then(() => {
|
|
||||||
selfMessage.react(emoji.cancel);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const filter = (reaction, user) => {
|
|
||||||
return ((reaction.emoji.name == emoji.next) || (reaction.emoji.name == emoji.confirm) || (reaction.emoji.name == emoji.previous) || (reaction.emoji.name == emoji.cancel)) && user.id == message.author.id;
|
|
||||||
}
|
|
||||||
const collector = selfMessage.createReactionCollector(filter, { time: 120000 });
|
|
||||||
|
|
||||||
collector.on('collect', (reaction, user) => {
|
|
||||||
switch (reaction.emoji.name) {
|
|
||||||
case emoji.next:
|
|
||||||
if (i < res.length) {
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
selfMessage.channel.send('That\'s the last GIF, sorry!');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data.embed_url = res[i].media[0].gif.url;
|
|
||||||
embed = functions.createGifEmbed(data, message.author, `${file.name}.${file.extension}`);
|
|
||||||
if (selfMessage.editable) {
|
|
||||||
selfMessage.edit(embed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case emoji.confirm:
|
|
||||||
channel.send('GIF Selected. What should I save the GIF as? (don\'t include the `.gif`)\nReact with ' + emoji.cancel + ' to cancel.')
|
|
||||||
.then(nameQueryMessage => {
|
|
||||||
nameQueryMessage.react(emoji.cancel);
|
|
||||||
const cancelReactFilter = (reaction, user) => {
|
|
||||||
return (reaction.emoji.name == emoji.cancel) && (user.id == message.author.id);
|
|
||||||
}
|
|
||||||
const cancelReactCollector = nameQueryMessage.createReactionCollector(cancelReactFilter, { time: 20000, max: 1 });
|
|
||||||
|
|
||||||
cancelReactCollector.on('collect', (reaction, user) => {
|
|
||||||
nameCollector.stop('cancel');
|
|
||||||
if (selfMessage.deletable) selfMessage.delete();
|
|
||||||
if (nameQueryMessage.deletable) nameQueryMessage.delete();
|
|
||||||
})
|
|
||||||
const nameCollectorFilter = nameMessage => nameMessage.author == message.author;
|
|
||||||
const nameCollector = nameQueryMessage.channel.createMessageCollector(nameCollectorFilter, { time: 30000, max: 1 });
|
|
||||||
|
|
||||||
nameCollector.on('collect', nameMessage => {
|
|
||||||
channel.send('The GIF has been saved as: ' + nameMessage.content + '.gif');
|
|
||||||
functions.saveGif(message, nameMessage.content.toLowerCase(), data.embed_url);
|
|
||||||
});
|
|
||||||
nameCollector.on('end', (collected, reason) => {
|
|
||||||
switch (reason) {
|
|
||||||
case 'cancel':
|
|
||||||
channel.send('The action has been canceled.');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
collector.stop("confirm");
|
|
||||||
break;
|
|
||||||
case emoji.previous:
|
|
||||||
if (i > 0) {
|
|
||||||
i--;
|
|
||||||
} else {
|
|
||||||
selfMessage.channel.send('That\'s the first GIF, can\'t go back any further!');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data.embed_url = res[i].media[0].gif.url;
|
|
||||||
embed = functions.createGifEmbed(data, message.author, `${file.name}.${file.extension}`);
|
|
||||||
if (selfMessage.editable) {
|
|
||||||
selfMessage.edit(embed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case emoji.cancel:
|
|
||||||
collector.stop('cancel');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
channel.send('There was an error, sorry.');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
collector.on('end', (collected, reason) => {
|
|
||||||
switch (reason) {
|
|
||||||
case 'cancel':
|
|
||||||
selfMessage.delete();
|
|
||||||
channel.send('The action has been canceled.');
|
|
||||||
break;
|
|
||||||
case 'messageDelete':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}).catch(err => console.error(err));
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'savepasta',
|
|
||||||
description: 'Saves a copypasta as pasta_name.pasta, just send the pasta name on the first message, and the bot will ask for the actual pasta afterwards.',
|
|
||||||
usage: '<Pasta Name>',
|
|
||||||
execute(message, file) {
|
|
||||||
message.channel.send(`I'll be saving the next message you send as ${file.name}.pasta\nWhat is the content of the copypasta?`)
|
|
||||||
.then(promptMessage => {
|
|
||||||
const pastaFilter = pastaMessage => pastaMessage.author == message.author;
|
|
||||||
const pastaCollector = promptMessage.channel.createMessageCollector(pastaFilter, { time: 30000, max: 1 });
|
|
||||||
|
|
||||||
pastaCollector.on('collect', pastaMessage => {
|
|
||||||
message.channel.send(functions.savePasta(message, file.name.toLowerCase(), functions.cleanInput(pastaMessage.content)));
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
const fn = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'sendhelp',
|
|
||||||
description: 'Send the help message to the current channel',
|
|
||||||
permissions: 'BOT_MOD', // To be implemented later
|
|
||||||
execute(message, file) {
|
|
||||||
message.channel.send(fn.createHelpEmbed(message));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'spongebob',
|
|
||||||
description: 'SpOnGeBoB-iFy AnYtHiNg AuToMaTiCaLly',
|
|
||||||
usage: '<text to convert>',
|
|
||||||
execute(message, file) {
|
|
||||||
let flipper = 0;
|
|
||||||
let newText = '';
|
|
||||||
for (const letter of file.name) {
|
|
||||||
if (flipper == 0) {
|
|
||||||
newText = newText + letter.toUpperCase();
|
|
||||||
flipper = 1;
|
|
||||||
} else {
|
|
||||||
newText = newText + letter;
|
|
||||||
flipper = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
message.channel.send(`@${message.author.username}: ${newText}`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
var axios = require("axios").default;
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
method: 'GET',
|
|
||||||
url: 'https://yahoo-finance-low-latency.p.rapidapi.com/v6/finance/quote',
|
|
||||||
params: {symbols: ''},
|
|
||||||
headers: {
|
|
||||||
'x-rapidapi-key': '0b3f85bcb7msh1e6e80e963c9914p1d1934jsnc3542fc83520',
|
|
||||||
'x-rapidapi-host': 'yahoo-finance-low-latency.p.rapidapi.com'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'stonk',
|
|
||||||
description: 'Get stonk details from Yahoo Finance',
|
|
||||||
execute(message, file) {
|
|
||||||
options.params.symbols = file.name;
|
|
||||||
axios.request(options).then(function (response) {
|
|
||||||
|
|
||||||
}).catch(function (error) {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
const axios = require('axios').default;
|
|
||||||
const options = {
|
|
||||||
method: 'GET',
|
|
||||||
url: 'https://brianiswu-otreeba-open-cannabis-v1.p.rapidapi.com/strains',
|
|
||||||
headers: {
|
|
||||||
'x-rapidapi-key': '0b3f85bcb7msh1e6e80e963c9914p1d1934jsnc3542fc83520',
|
|
||||||
'x-rapidapi-host': 'brianiswu-otreeba-open-cannabis-v1.p.rapidapi.com'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'strain',
|
|
||||||
description: 'Search for information about a cannabis strain. Powered by Otreeba',
|
|
||||||
execute(message, file) {
|
|
||||||
options.url = options.url + '?name=' + file.name;
|
|
||||||
axios.request(options).then(function (response) {
|
|
||||||
console.log(response.data);
|
|
||||||
}).catch(function (error) {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
const fn = require('../functions.js');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
execute(message, file) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: "truth",
|
|
||||||
description: "The truth about MHFS",
|
|
||||||
execute(message, args) {
|
|
||||||
message.channel.send("https://www.twitch.tv/hochmania/clip/EsteemedSlickDootStinkyCheese-hncmP8aIP8_WQb_a?filter=clips&range=all&sort=time");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: 'upload',
|
|
||||||
description: '',
|
|
||||||
execute(message, file) {
|
|
||||||
const fn = require('../functions');
|
|
||||||
|
|
||||||
fn.uploadGIFs(message);
|
|
||||||
|
|
||||||
message.reply('Uploaded, I hope.');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
const functions = require('../functions.js');
|
|
||||||
const axios = require("axios").default;
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
method: 'GET',
|
|
||||||
url: 'https://weatherapi-com.p.rapidapi.com/current.json',
|
|
||||||
params: {q: ''},
|
|
||||||
headers: {
|
|
||||||
'x-rapidapi-key': '0b3f85bcb7msh1e6e80e963c9914p1d1934jsnc3542fc83520',
|
|
||||||
'x-rapidapi-host': 'weatherapi-com.p.rapidapi.com'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'weather',
|
|
||||||
description: 'Get the current weather by ZIP code or city name.',
|
|
||||||
usage: '<ZIP code, City Name, etc>',
|
|
||||||
execute(message, file) {
|
|
||||||
options.params.q = file.name;
|
|
||||||
axios.request(options).then(function (response) {
|
|
||||||
const embed = functions.createWeatherEmbed(response.data, message.author, `${file.name}.${file.extension}`);
|
|
||||||
message.channel.send(embed).then().catch(err => console.error(err));
|
|
||||||
}).catch(function (error) {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
name: "wrongbad",
|
|
||||||
description: "",
|
|
||||||
execute(message, args) {
|
|
||||||
|
|
||||||
const wrongbad = "<:wrongbad:853304921969393684>";
|
|
||||||
message.channel.send("");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,8 @@
|
|||||||
{
|
{
|
||||||
"validExtensions": []
|
"isDev": true,
|
||||||
|
"clientId": "513184762073055252",
|
||||||
|
"guildId": "760701839427108874",
|
||||||
|
"devChannelId": "868545469381480498",
|
||||||
|
"guildName": "CumbHub",
|
||||||
|
"validCommands": []
|
||||||
}
|
}
|
36
dot-commands/gif.js
Normal file
36
dot-commands/gif.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
const fn = require('../functions');
|
||||||
|
const tenor = require('tenorjs').client({
|
||||||
|
"Key": process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration
|
||||||
|
"Filter": "off", // "off", "low", "medium", "high", not case sensitive
|
||||||
|
"Locale": "en_US", // Your locale here, case-sensitivity depends on input
|
||||||
|
"MediaFilter": "minimal", // either minimal or basic, not case sensitive
|
||||||
|
"DateFormat": "D/MM/YYYY - H:mm:ss A" // Change this accordingly
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'gif',
|
||||||
|
description: 'Send a GIF',
|
||||||
|
usage: '<GIF name or Search Query>.gif',
|
||||||
|
execute(message, commandData) {
|
||||||
|
if (message.deletable) message.delete();
|
||||||
|
const client = message.client;
|
||||||
|
if (!client.gifs.has(commandData.args)) {
|
||||||
|
tenor.Search.Query(commandData.args, 1).then(res => {
|
||||||
|
if (res[0] == undefined) {
|
||||||
|
message.reply('Sorry I was unable to find a GIF of ' + commandData.args);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
commandData.embed_url = res[0].media[0].gif.url;
|
||||||
|
// message.reply(fn.embeds.gif(commandData));
|
||||||
|
message.channel.send(`> ${commandData.author} - ${commandData.args}.gif`);
|
||||||
|
message.channel.send(commandData.embed_url);
|
||||||
|
}).catch(err => console.error(err));
|
||||||
|
} else {
|
||||||
|
// message.reply(commandData.args + ' requested by ' + message.author.username + '\n' + client.gifs.get(commandData.args).embed_url);
|
||||||
|
commandData.embed_url = client.gifs.get(commandData.args).embed_url;
|
||||||
|
// message.reply(fn.embeds.gif(commandData));
|
||||||
|
message.channel.send(`> ${commandData.author} - ${commandData.args}.gif`);
|
||||||
|
message.channel.send(commandData.embed_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
dot-commands/pasta.js
Normal file
19
dot-commands/pasta.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'pasta',
|
||||||
|
description: 'Send a copypasta.',
|
||||||
|
usage: '<Copypasta Name>.pasta',
|
||||||
|
execute(message, commandData) {
|
||||||
|
const client = message.client;
|
||||||
|
let replyBody = '';
|
||||||
|
let iconUrl;
|
||||||
|
if (!client.pastas.has(commandData.args)) {
|
||||||
|
commandData.content = 'Sorry I couldn\'t find that pasta.';
|
||||||
|
} else {
|
||||||
|
commandData.content = client.pastas.get(commandData.args).content;
|
||||||
|
commandData.iconUrl = client.pastas.get(commandData.args).iconUrl;
|
||||||
|
}
|
||||||
|
message.reply(fn.embeds.pasta(commandData));
|
||||||
|
}
|
||||||
|
}
|
17
dot-commands/request.js
Normal file
17
dot-commands/request.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'request',
|
||||||
|
description: 'Submit a request to the bot developer.',
|
||||||
|
usage: '<request or feedback>.request',
|
||||||
|
execute(message, commandData) {
|
||||||
|
const request = commandData.args;
|
||||||
|
commandData.content = `Your request has been submitted!\nRequest: ${request}`;
|
||||||
|
message.reply(fn.embeds.text(commandData));
|
||||||
|
commandData.content = `A new request has been submitted by ${message.author.tag}:\n${commandData.args}`;
|
||||||
|
message.client.users.fetch(process.env.ownerID).then(user => {
|
||||||
|
user.send(fn.embeds.text(commandData));
|
||||||
|
}).catch(error => { console.error(error); });
|
||||||
|
fn.upload.request(commandData, message.client);
|
||||||
|
},
|
||||||
|
};
|
34
dot-commands/spongebob.js
Normal file
34
dot-commands/spongebob.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const functions = require('../functions.js');
|
||||||
|
const config = require('../config.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'spongebob',
|
||||||
|
description: 'SpOnGeBoB-iFy AnYtHiNg AuToMaTiCaLly',
|
||||||
|
usage: '<text to convert>.spongebob',
|
||||||
|
execute(message, commandData) {
|
||||||
|
let flipper = 0;
|
||||||
|
let newText = '';
|
||||||
|
for (const letter of commandData.args) {
|
||||||
|
if (letter == ' ') {
|
||||||
|
newText = newText + letter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (letter == 'i' || letter == 'I') {
|
||||||
|
newText = newText + 'i';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (letter == 'l' || letter == 'L') {
|
||||||
|
newText = newText + 'L';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flipper == 0) {
|
||||||
|
newText = newText + letter.toUpperCase();
|
||||||
|
flipper = 1;
|
||||||
|
} else {
|
||||||
|
newText = newText + letter;
|
||||||
|
flipper = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message.reply(`@${message.author.username}: ${newText}`);
|
||||||
|
}
|
||||||
|
}
|
17
dot-commands/strain.js
Normal file
17
dot-commands/strain.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const fn = require('../functions');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'strain',
|
||||||
|
description: 'Search for information about a cannabis strain.',
|
||||||
|
usage: '<strain name>.strain',
|
||||||
|
execute(message, commandData) {
|
||||||
|
commandData.strainName = fn.weed.strain.lookup(commandData.args, message.client);
|
||||||
|
if (commandData.strainName) {
|
||||||
|
fn.download.strain(commandData, message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
commandData.content = 'Sorry, I couldn\'t find a strain with that name: ' + commandData.args;
|
||||||
|
message.reply(fn.embeds.text(commandData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
671
functions.js
671
functions.js
@ -1,304 +1,439 @@
|
|||||||
const Discord = require('discord.js');
|
/* eslint-disable comma-dangle */
|
||||||
const fs = require('fs');
|
// dotenv for handling environment variables
|
||||||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
|
const dotenv = require('dotenv');
|
||||||
const config = require('./config.json');
|
dotenv.config();
|
||||||
const pg = require('pg');
|
// Assignment of environment variables
|
||||||
let dbConnected = false;
|
const dbHost = process.env.dbHost;
|
||||||
const db = new pg.Client({
|
const dbUser = process.env.dbUser;
|
||||||
connectionString: process.env.DATABASE_URL,
|
const dbName = process.env.dbName;
|
||||||
ssl: {
|
const dbPass = process.env.dbPass;
|
||||||
rejectUnauthorized: false
|
const dbPort = process.env.dbPort;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// filesystem
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// D.js
|
||||||
|
const Discord = require('discord.js');
|
||||||
|
|
||||||
|
// Fuzzy text matching for db lookups
|
||||||
|
const FuzzySearch = require('fuzzy-search');
|
||||||
|
|
||||||
|
// Various imports
|
||||||
|
const config = require('./config.json');
|
||||||
|
const strings = require('./strings.json');
|
||||||
|
const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js'));
|
||||||
|
const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js'));
|
||||||
|
|
||||||
|
// MySQL
|
||||||
|
const mysql = require('mysql');
|
||||||
|
const db = new mysql.createConnection({
|
||||||
|
host: dbHost,
|
||||||
|
user: dbUser,
|
||||||
|
password: dbPass,
|
||||||
|
database: dbName,
|
||||||
|
port: dbPort,
|
||||||
|
});
|
||||||
db.connect();
|
db.connect();
|
||||||
|
|
||||||
module.exports = {
|
const functions = {
|
||||||
setValidExtensions(client) {
|
collections: {
|
||||||
for (const entry of client.commands.map(command => command.name)) {
|
slashCommands(client) {
|
||||||
config.validExtensions.push(entry);
|
if (!client.slashCommands) client.slashCommands = new Discord.Collection();
|
||||||
|
client.slashCommands.clear();
|
||||||
|
for (const file of slashCommandFiles) {
|
||||||
|
const slashCommand = require(`./slash-commands/${file}`);
|
||||||
|
if (slashCommand.data != undefined) {
|
||||||
|
client.slashCommands.set(slashCommand.data.name, slashCommand);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
getCommandFiles(client) {
|
|
||||||
if (!client.commands) client.commands = new Discord.Collection();
|
|
||||||
client.commands.clear();
|
|
||||||
for (const file of commandFiles) {
|
|
||||||
const command = require(`./commands/${file}`);
|
|
||||||
client.commands.set(command.name, command);
|
|
||||||
}
|
}
|
||||||
|
if (config.isDev) console.log('Slash Commands Collection Built');
|
||||||
},
|
},
|
||||||
getGifFiles(client) {
|
setvalidCommands(client) {
|
||||||
|
for (const entry of client.dotCommands.map(command => command.name)) {
|
||||||
|
config.validCommands.push(entry);
|
||||||
|
}
|
||||||
|
if (config.isDev) console.log('Valid Commands Added to Config');
|
||||||
|
},
|
||||||
|
dotCommands(client) {
|
||||||
|
if (!client.dotCommands) client.dotCommands = new Discord.Collection();
|
||||||
|
client.dotCommands.clear();
|
||||||
|
for (const file of dotCommandFiles) {
|
||||||
|
const dotCommand = require(`./dot-commands/${file}`);
|
||||||
|
client.dotCommands.set(dotCommand.name, dotCommand);
|
||||||
|
}
|
||||||
|
if (config.isDev) console.log('Dot Commands Collection Built');
|
||||||
|
},
|
||||||
|
gifs(rows, client) {
|
||||||
if (!client.gifs) client.gifs = new Discord.Collection();
|
if (!client.gifs) client.gifs = new Discord.Collection();
|
||||||
client.gifs.clear();
|
client.gifs.clear();
|
||||||
const query = "SELECT name, embed_url FROM gifs";
|
for (const row of rows) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(query)
|
|
||||||
.then(res => {
|
|
||||||
for (let row of res.rows) {
|
|
||||||
const gif = {
|
const gif = {
|
||||||
|
id: row.id,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
embed_url: row.embed_url
|
embed_url: row.embed_url
|
||||||
};
|
};
|
||||||
client.gifs.set(gif.name, gif);
|
client.gifs.set(gif.name, gif);
|
||||||
}
|
}
|
||||||
resolve();
|
if (config.isDev) console.log('GIFs Collection Built');
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
getPotPhrases(client) {
|
joints(rows, client) {
|
||||||
if (!client.potphrases) client.potphrases = new Discord.Collection();
|
if (!client.joints) client.joints = new Discord.Collection();
|
||||||
client.potphrases.clear();
|
client.joints.clear();
|
||||||
const query = "SELECT id, content FROM potphrases";
|
for (const row of rows) {
|
||||||
db.query(query)
|
const joint = {
|
||||||
.then(res => {
|
|
||||||
for (let row of res.rows) {
|
|
||||||
const potphrase = {
|
|
||||||
id: row.id,
|
id: row.id,
|
||||||
content: row.content
|
content: row.content
|
||||||
};
|
};
|
||||||
client.potphrases.set(potphrase.id, potphrase);
|
client.joints.set(joint.id, joint);
|
||||||
}
|
}
|
||||||
})
|
if (config.isDev) console.log('Joints Collection Built');
|
||||||
.catch(err => console.error(err));
|
|
||||||
},
|
},
|
||||||
getPastaFiles(client) {
|
pastas(rows, client) {
|
||||||
if (!client.pastas) client.pastas = new Discord.Collection();
|
if (!client.pastas) client.pastas = new Discord.Collection();
|
||||||
client.pastas.clear();
|
client.pastas.clear();
|
||||||
const query = "SELECT name, content, iconurl FROM pastas";
|
for (const row of rows) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
db.query(query)
|
|
||||||
.then(res => {
|
|
||||||
for (let row of res.rows) {
|
|
||||||
const pasta = {
|
const pasta = {
|
||||||
|
id: row.id,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
content: row.content,
|
content: row.content,
|
||||||
iconUrl: row.iconurl
|
iconUrl: row.iconurl,
|
||||||
};
|
};
|
||||||
client.pastas.set(pasta.name, pasta);
|
client.pastas.set(pasta.name, pasta);
|
||||||
}
|
}
|
||||||
resolve();
|
if (config.isDev) console.log('Pastas Collection Built');
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
reload(client) {
|
requests(rows, client) {
|
||||||
this.getCommandFiles(client);
|
if (!client.requests) client.requests = new Discord.Collection();
|
||||||
this.getGifFiles(client);
|
client.requests.clear();
|
||||||
this.getPastaFiles(client);
|
|
||||||
this.getPotPhrases(client);
|
|
||||||
},
|
|
||||||
getFileInfo(content) {
|
|
||||||
// Split the message content at the final instance of a period
|
|
||||||
const finalPeriod = content.lastIndexOf('.');
|
|
||||||
if (finalPeriod < 0) return false;
|
|
||||||
const extension = content.slice(finalPeriod).replace('.','').toLowerCase();
|
|
||||||
const filename = content.slice(0,finalPeriod).toLowerCase();
|
|
||||||
const file = {
|
|
||||||
name: filename,
|
|
||||||
extension: extension
|
|
||||||
};
|
|
||||||
return file;
|
|
||||||
},
|
|
||||||
extIsValid(extension) {
|
|
||||||
const extensions = require('./config.json').validExtensions;
|
|
||||||
return extensions.includes(extension);
|
|
||||||
},
|
|
||||||
cleanInput(string) {
|
|
||||||
return string.replace(/'/g, "''").replace(/\n/g, '\\n');
|
|
||||||
},
|
|
||||||
createGifEmbed(data, author, command) {
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Command: ' + command)
|
|
||||||
.setImage(data.embed_url)
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${author.username}#${author.discriminator}`);
|
|
||||||
},
|
|
||||||
saveGif(message, name, embed_url) {
|
|
||||||
const gif = {
|
|
||||||
name: name,
|
|
||||||
embed_url: embed_url
|
|
||||||
};
|
|
||||||
message.client.gifs.set(gif.name, gif);
|
|
||||||
this.uploadGIF(name, embed_url);
|
|
||||||
},
|
|
||||||
savePasta(message, name, content) {
|
|
||||||
const pasta = {
|
|
||||||
name: name,
|
|
||||||
content: content
|
|
||||||
};
|
|
||||||
message.client.pastas.set(pasta.name, pasta);
|
|
||||||
|
|
||||||
const query = `INSERT INTO pastas (name, content) VALUES ('${name}','${content}')`;
|
|
||||||
db.query(query);
|
|
||||||
|
|
||||||
return "Success";
|
|
||||||
},
|
|
||||||
createAirportEmbed(data, author, command) {
|
|
||||||
const airport = data.airport[0];
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Command: ' + command)
|
|
||||||
.setTitle(airport.airport_name)
|
|
||||||
.addFields(
|
|
||||||
{ name: 'Location', value: `${airport.city}, ${airport.state_abbrev}`, inline: true },
|
|
||||||
{ name: 'Coordinates', value: `${airport.latitude}, ${airport.longitude}`, inline: true },
|
|
||||||
{ name: 'Elevation', value: `${airport.elevation}ft`, inline: true },
|
|
||||||
{ name: 'More Information', value: airport.link_path }
|
|
||||||
)
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${author.username}#${author.discriminator}`);
|
|
||||||
},
|
|
||||||
createWeatherEmbed(data, author, command) {
|
|
||||||
const loc = data.location;
|
|
||||||
const weather = data.current;
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Command: ' + command)
|
|
||||||
.setTitle(`${loc.name}, ${loc.region}, ${loc.country} Weather`)
|
|
||||||
.setDescription(`The weather is currently ${weather.condition.text}`)
|
|
||||||
.addFields(
|
|
||||||
{ name: 'Temperature', value: `${weather.temp_f}°F (Feels like: ${weather.feelslike_f}°F)`, inline: true },
|
|
||||||
{ name: 'Winds', value: `${weather.wind_mph} ${weather.wind_dir}`, inline: true },
|
|
||||||
{ name: 'Pressure', value: `${weather.pressure_in}inHg`, inline: true },
|
|
||||||
{ name: 'Relative Humidity', value: `${weather.humidity}%`, inline: true }
|
|
||||||
)
|
|
||||||
.setThumbnail(`https:${weather.condition.icon}`)
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${author.username}#${author.discriminator}`);
|
|
||||||
},
|
|
||||||
textEmbed(content, author, command) {
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Command: ' + command)
|
|
||||||
.setDescription(content)
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${author.username}#${author.discriminator}`);
|
|
||||||
},
|
|
||||||
pastaEmbed(content, iconUrl, author) {
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Command: ' + 'pasta')
|
|
||||||
.setDescription(content)
|
|
||||||
.setThumbnail(iconUrl)
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${author.username}#${author.discriminator}`);
|
|
||||||
},
|
|
||||||
createStockEmbed(data, author, command) {
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Command: ' + command)
|
|
||||||
.setTitle()
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${author.username}#${author.discriminator}`);
|
|
||||||
},
|
|
||||||
createHelpEmbed(message) {
|
|
||||||
const { commands } = message.client;
|
|
||||||
let fields = [];
|
|
||||||
for (const entry of commands.map(command => [command.name, command.description, command.usage])) {
|
|
||||||
const name = entry[0];
|
|
||||||
const description = entry[1];
|
|
||||||
let usage;
|
|
||||||
if (entry[2] == undefined) {
|
|
||||||
usage = '';
|
|
||||||
} else {
|
|
||||||
usage = entry[2];
|
|
||||||
}
|
|
||||||
const excludeList = [
|
|
||||||
'kill',
|
|
||||||
'mapcommands',
|
|
||||||
'newgif',
|
|
||||||
'newpng',
|
|
||||||
'oldgif',
|
|
||||||
'strain',
|
|
||||||
'stonk',
|
|
||||||
'wrongbad'
|
|
||||||
];
|
|
||||||
if (excludeList.includes(name)) continue;
|
|
||||||
fields.push({
|
|
||||||
name: name,
|
|
||||||
value: `${description}\n**Usage:** \`${usage}.${name}\``
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('NodBot Help')
|
|
||||||
.setDescription('All commands are provided as "file extensions" instead of prefixes to the message.')
|
|
||||||
.addFields(fields)
|
|
||||||
.setTimestamp();
|
|
||||||
},
|
|
||||||
createGIFList(message) {
|
|
||||||
let list = [];
|
|
||||||
const { gifs } = message.client;
|
|
||||||
for (const entry of gifs.map(gif => [gif.name])) {
|
|
||||||
list.push(entry[0] + '.gif');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('NodBot GIF List')
|
|
||||||
.setTitle('List of Currently Saved GIFs')
|
|
||||||
.setDescription(list.join('\n'))
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${message.author.username}#${message.author.discriminator}`);
|
|
||||||
},
|
|
||||||
createPastaList(message) {
|
|
||||||
let list = [];
|
|
||||||
const { pastas } = message.client;
|
|
||||||
for (const entry of pastas.map(pasta => [pasta.name])) {
|
|
||||||
list.push(entry[0] + '.pasta');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor('NodBot Pasta List')
|
|
||||||
.setTitle('List of Currently Saved Copypastas')
|
|
||||||
.setDescription(list.join('\n'))
|
|
||||||
.setTimestamp()
|
|
||||||
.setFooter(`@${message.author.username}#${message.author.discriminator}`);
|
|
||||||
},
|
|
||||||
uploadGIF(name, embed_url) {
|
|
||||||
const query = `INSERT INTO gifs (name, embed_url) VALUES ('${name}','${embed_url}')`;
|
|
||||||
db.query(query)
|
|
||||||
.then()
|
|
||||||
.catch(e => console.error(e));
|
|
||||||
},
|
|
||||||
uploadPotPhrase(content) {
|
|
||||||
const query = `INSERT INTO potphrases (content) VALUES ('${content}')`;
|
|
||||||
db.query(query)
|
|
||||||
.then()
|
|
||||||
.catch(e => console.error(e));
|
|
||||||
},
|
|
||||||
uploadRequest(author, request) {
|
|
||||||
const query = `INSERT INTO requests (author, request, status) VALUES ('@${author.username}#${author.discriminator}','${request}','Active')`;
|
|
||||||
db.query(query)
|
|
||||||
.then()
|
|
||||||
.catch(e => console.error(e));
|
|
||||||
},
|
|
||||||
getActiveRequests(message) {
|
|
||||||
const query = "SELECT * FROM requests WHERE status = 'Active'";
|
|
||||||
let rows;
|
|
||||||
db.query(query)
|
|
||||||
.then(res => {
|
|
||||||
const embed = this.requestsEmbed(res.rows);
|
|
||||||
message.channel.send(embed);
|
|
||||||
})
|
|
||||||
.catch(e => console.error(e));
|
|
||||||
return rows;
|
|
||||||
},
|
|
||||||
requestsEmbed(rows) {
|
|
||||||
let fields = [];
|
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
fields.push({
|
const request = {
|
||||||
name: '#' + row.id,
|
id: row.id,
|
||||||
value: row.request + `\nSubmitted by ${row.author}`
|
author: row.author,
|
||||||
|
request: row.request,
|
||||||
|
};
|
||||||
|
client.requests.set(request.id, request);
|
||||||
|
}
|
||||||
|
if (config.isDev) console.log('Requests Collection Built');
|
||||||
|
},
|
||||||
|
strains(rows, client) {
|
||||||
|
if (!client.strains) client.strains = new Discord.Collection();
|
||||||
|
client.strains.clear();
|
||||||
|
for (const row of rows) {
|
||||||
|
const strain = {
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
};
|
||||||
|
client.strains.set(strain.name, strain);
|
||||||
|
}
|
||||||
|
if (config.isDev) console.log('Strains Collection Built');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dot: {
|
||||||
|
getCommandData(message) {
|
||||||
|
const commandData = {};
|
||||||
|
// Split the message content at the final instance of a period
|
||||||
|
const finalPeriod = message.content.lastIndexOf('.');
|
||||||
|
if (finalPeriod < 0) {
|
||||||
|
commandData.isCommand = false;
|
||||||
|
return commandData;
|
||||||
|
}
|
||||||
|
commandData.isCommand = true;
|
||||||
|
commandData.args = message.content.slice(0,finalPeriod);
|
||||||
|
commandData.command = message.content.slice(finalPeriod).replace('.','').toLowerCase();
|
||||||
|
commandData.author = `${message.author.username}#${message.author.discriminator}`;
|
||||||
|
return this.checkCommand(commandData);
|
||||||
|
},
|
||||||
|
checkCommand(commandData) {
|
||||||
|
if (commandData.isCommand) {
|
||||||
|
const validCommands = require('./config.json').validCommands;
|
||||||
|
commandData.isValid = validCommands.includes(commandData.command);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
commandData.isValid = false;
|
||||||
|
console.error('Somehow a non-command made it to checkCommands()');
|
||||||
|
}
|
||||||
|
return commandData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
embeds: {
|
||||||
|
help(interaction) {
|
||||||
|
// Construct the Help Embed
|
||||||
|
const helpEmbed = new Discord.MessageEmbed()
|
||||||
|
.setColor('BLUE')
|
||||||
|
.setAuthor('Help Page')
|
||||||
|
.setDescription(strings.help.description)
|
||||||
|
.setThumbnail(strings.urls.avatar);
|
||||||
|
|
||||||
|
// Construct the Slash Commands help
|
||||||
|
|
||||||
|
let slashCommandsFields = [];
|
||||||
|
|
||||||
|
const slashCommandsMap = interaction.client.slashCommands.map(e => {
|
||||||
|
return {
|
||||||
|
name: e.data.name,
|
||||||
|
description: e.data.description
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const e of slashCommandsMap) {
|
||||||
|
slashCommandsFields.push({
|
||||||
|
name: `- /${e.name}`,
|
||||||
|
value: e.description,
|
||||||
|
inline: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Discord.MessageEmbed()
|
// Construct the Dot Commands Help
|
||||||
.setAuthor('NodBot Requests')
|
let dotCommandsFields = [];
|
||||||
.setTitle('Currently Active Requests')
|
|
||||||
.addFields(fields)
|
const dotCommandsMap = interaction.client.dotCommands.map(e => {
|
||||||
.setTimestamp();
|
return {
|
||||||
|
name: e.name,
|
||||||
|
description: e.description,
|
||||||
|
usage: e.usage
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const e of dotCommandsMap) {
|
||||||
|
dotCommandsFields.push({
|
||||||
|
name: `- .${e.name}`,
|
||||||
|
value: `${e.description}\nUsage: ${e.usage}`,
|
||||||
|
inline: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
helpEmbed.addField('Slash Commands', strings.help.slash);
|
||||||
|
helpEmbed.addFields(slashCommandsFields);
|
||||||
|
helpEmbed.addField('Dot Commands', strings.help.dot);
|
||||||
|
helpEmbed.addFields(dotCommandsFields);
|
||||||
|
|
||||||
|
return { embeds: [
|
||||||
|
helpEmbed
|
||||||
|
]};
|
||||||
},
|
},
|
||||||
closeRequest(id) {
|
gif(commandData) {
|
||||||
const query = `UPDATE requests SET status = 'Closed' WHERE id = ${id}`;
|
return { embeds: [new Discord.MessageEmbed()
|
||||||
db.query(query)
|
.setAuthor(`${commandData.args}.${commandData.command}`)
|
||||||
.then()
|
.setImage(commandData.embed_url)
|
||||||
.catch(e => console.error(e));
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author)]};
|
||||||
|
},
|
||||||
|
pasta(commandData) {
|
||||||
|
return { embeds: [ new Discord.MessageEmbed()
|
||||||
|
.setAuthor(`${commandData.args}.${commandData.command}`)
|
||||||
|
.setDescription(commandData.content)
|
||||||
|
.setThumbnail(commandData.iconUrl)
|
||||||
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author)]};
|
||||||
|
},
|
||||||
|
pastas(commandData) {
|
||||||
|
const pastasArray = [];
|
||||||
|
const pastasEmbed = new Discord.MessageEmbed()
|
||||||
|
.setAuthor(commandData.command)
|
||||||
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author);
|
||||||
|
|
||||||
|
for (const row of commandData.pastas) {
|
||||||
|
pastasArray.push(`#${row.id} - ${row.name}.pasta`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pastasString = pastasArray.join('\n');
|
||||||
|
pastasEmbed.setDescription(pastasString);
|
||||||
|
|
||||||
|
return { embeds: [pastasEmbed] };
|
||||||
|
},
|
||||||
|
gifs(commandData) {
|
||||||
|
const gifsArray = [];
|
||||||
|
const gifsEmbed = new Discord.MessageEmbed()
|
||||||
|
.setAuthor(commandData.command)
|
||||||
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author);
|
||||||
|
|
||||||
|
for (const row of commandData.gifs) {
|
||||||
|
gifsArray.push(`#${row.id} - ${row.name}.gif`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gifsString = gifsArray.join('\n');
|
||||||
|
gifsEmbed.setDescription(gifsString);
|
||||||
|
|
||||||
|
return { embeds: [gifsEmbed] };
|
||||||
|
},
|
||||||
|
text(commandData) {
|
||||||
|
return { embeds: [new Discord.MessageEmbed()
|
||||||
|
.setAuthor(commandData.command)
|
||||||
|
.setDescription(commandData.content)
|
||||||
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author)]};
|
||||||
|
},
|
||||||
|
requests(commandData) {
|
||||||
|
const requestsEmbed = new Discord.MessageEmbed()
|
||||||
|
.setAuthor(commandData.command)
|
||||||
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author);
|
||||||
|
|
||||||
|
const requestsArray = [];
|
||||||
|
|
||||||
|
for (const row of commandData.requests) {
|
||||||
|
requestsArray.push(
|
||||||
|
`**#${row.id} - ${row.author}**`,
|
||||||
|
`Request: ${row.request}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestsEmbed.setDescription(requestsArray.join('\n'));
|
||||||
|
|
||||||
|
return { embeds: [requestsEmbed]};
|
||||||
|
},
|
||||||
|
strain(commandData, message) {
|
||||||
|
const strainEmbed = new Discord.MessageEmbed()
|
||||||
|
.setAuthor(`${commandData.command} #${commandData.strainInfo.id}`)
|
||||||
|
.setTimestamp()
|
||||||
|
.setFooter(commandData.author);
|
||||||
|
const { strainInfo } = commandData;
|
||||||
|
strainEmbed.addFields([
|
||||||
|
{
|
||||||
|
name: 'Strain Name',
|
||||||
|
value: `${strainInfo.name}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Type',
|
||||||
|
value: `${strainInfo.type}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Effects',
|
||||||
|
value: `${strainInfo.effects}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Treats',
|
||||||
|
value: `${strainInfo.ailments}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Flavor',
|
||||||
|
value: `${strainInfo.flavor}`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
message.reply({ embeds: [ strainEmbed ]});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
collect: {
|
||||||
|
gifName(interaction) {
|
||||||
|
const gifNameFilter = m => m.author.id == strings.temp.gifUserId;
|
||||||
|
return interaction.channel.createMessageCollector({ filter: gifNameFilter, time: 30000 });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
upload: {
|
||||||
|
request(commandData, client) {
|
||||||
|
const query = `INSERT INTO requests (author, request, status) VALUES ('${commandData.author}','${commandData.args}','Active')`;
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.download.requests(client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
pasta(pastaData, client) {
|
||||||
|
const query = `INSERT INTO pastas (name, content) VALUES ('${pastaData.name}','${pastaData.content}')`;
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.download.pastas(client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
joint(content, client) {
|
||||||
|
const query = `INSERT INTO joints (content) VALUES ('${content}')`;
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.download.joints(client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
gif(gifData, client) {
|
||||||
|
const query = `INSERT INTO gifs (name, embed_url) VALUES ('${gifData.name}', '${gifData.embed_url}')`;
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.download.gifs(client);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
download: {
|
||||||
|
requests(client) {
|
||||||
|
const query = 'SELECT * FROM requests WHERE status = \'Active\' ORDER BY id ASC';
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.collections.requests(rows, client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
pastas(client) {
|
||||||
|
const query = 'SELECT * FROM pastas ORDER BY id ASC';
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.collections.pastas(rows, client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
gifs(client) {
|
||||||
|
const query = 'SELECT * FROM gifs ORDER BY id ASC';
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.collections.gifs(rows, client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
joints(client) {
|
||||||
|
const query = 'SELECT * FROM joints ORDER BY id ASC';
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.collections.joints(rows, client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
strain(commandData, message) {
|
||||||
|
const { strainName } = commandData;
|
||||||
|
const query = `SELECT id, name, type, effects, ailment, flavor FROM strains WHERE name = '${strainName}'`;
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (rows != undefined) {
|
||||||
|
commandData.strainInfo = {
|
||||||
|
id: `${rows[0].id}`,
|
||||||
|
name: `${rows[0].name}`,
|
||||||
|
type: `${rows[0].type}`,
|
||||||
|
effects: `${rows[0].effects}`,
|
||||||
|
ailments: `${rows[0].ailment}`,
|
||||||
|
flavor: `${rows[0].flavor}`,
|
||||||
|
};
|
||||||
|
functions.embeds.strain(commandData, message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
strains(client) {
|
||||||
|
const query = 'SELECT id, name FROM strains';
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.collections.strains(rows, client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
weed: {
|
||||||
|
strain: {
|
||||||
|
lookup(strainName, client) {
|
||||||
|
const strainSearcher = new FuzzySearch(client.strains.map(e => e.name));
|
||||||
|
const name = strainSearcher.search(strainName)[0];
|
||||||
|
if (name != undefined) {
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submit(strainName) {
|
||||||
|
return strainName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// Parent-Level functions (miscellaneuous)
|
||||||
|
closeRequest(requestId, client) {
|
||||||
|
const query = `UPDATE requests SET status = 'Closed' WHERE id = ${requestId}`;
|
||||||
|
db.query(query, (err, rows, fields) => {
|
||||||
|
if (err) throw err;
|
||||||
|
functions.download.requests(client);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = functions;
|
72
index.js
72
index.js
@ -1,72 +0,0 @@
|
|||||||
// Variable Assignment
|
|
||||||
// Environment Variable Setup
|
|
||||||
const dotenv = require('dotenv');
|
|
||||||
dotenv.config();
|
|
||||||
// Discord.js library
|
|
||||||
const Discord = require('discord.js');
|
|
||||||
// Create the client
|
|
||||||
const client = new Discord.Client();
|
|
||||||
// External Functions File
|
|
||||||
const functions = require('./functions.js');
|
|
||||||
|
|
||||||
// Once the client is logged in and ready
|
|
||||||
client.once('ready', () => {
|
|
||||||
console.log('Ready');
|
|
||||||
// This sets the activity that shows below the bot's name in the member/friend list
|
|
||||||
client.user.setActivity('Nod Simulator 2021', { type: 'PLAYING' }).then().catch(console.error);
|
|
||||||
// Import the Command, GIF, and Pasta files into collections
|
|
||||||
functions.getCommandFiles(client);
|
|
||||||
functions.getGifFiles(client);
|
|
||||||
functions.getPastaFiles(client);
|
|
||||||
functions.getPotPhrases(client);
|
|
||||||
functions.setValidExtensions(client);
|
|
||||||
// Get the owner and DM them a message that the bot is ready, useful for remote deployment
|
|
||||||
client.users.fetch(process.env.ownerID).then(user => {
|
|
||||||
user.createDM().then(channel => {
|
|
||||||
channel.send('Ready');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Log into discord using the TOKEN provided by environment variables (.env)
|
|
||||||
client.login(process.env.TOKEN)
|
|
||||||
.then()
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
// Dump the TOKEN into the console as the TOKEN is likely the cause of any error logging in, unless Discord servers are down.
|
|
||||||
console.log('Token: ' + process.env.TOKEN)
|
|
||||||
});
|
|
||||||
|
|
||||||
// This runs on each message the bot sees
|
|
||||||
client.on('message', message => {
|
|
||||||
// Out here smoking big doinks in Amish
|
|
||||||
if ((message.content.toLowerCase().includes('big')) && message.content.toLowerCase().includes('doinks')) {
|
|
||||||
message.channel.send('gang.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the filename and extension as an array
|
|
||||||
const file = functions.getFileInfo(message.content);
|
|
||||||
if (!file) return;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If the message is from a bot, or doesn't have a valid file extension, stop here.
|
|
||||||
if (functions.extIsValid(file.extension) == false || message.author.bot) return;
|
|
||||||
|
|
||||||
// If the command collection doesn't contain the given command, stop here.
|
|
||||||
if (!client.commands.has(file.extension)) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Attempt to execute the command
|
|
||||||
client.commands.get(file.extension).execute(message, file);
|
|
||||||
} catch (error) {
|
|
||||||
// Log errors and let the user know something went wrong.
|
|
||||||
console.error(error);
|
|
||||||
message.channel.send('There was an error trying to execute that command.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to delete the requester's message
|
|
||||||
if (message.deletable) {
|
|
||||||
message.delete().then().catch(err => console.error(err));
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,25 +1,23 @@
|
|||||||
Slash Commands:
|
Slash Commands: [* means updated]
|
||||||
/closereq
|
*/closereq*
|
||||||
/gifs
|
*/gifs
|
||||||
/help
|
*/help*
|
||||||
/joint
|
*/joint*
|
||||||
/joints
|
*/joints*
|
||||||
/lenny
|
*/lenny*
|
||||||
/pastas
|
*/pastas*
|
||||||
/ping
|
*/ping*
|
||||||
/requests
|
*/requests*
|
||||||
/savejoint (prev. .roll)
|
*/savejoint (prev. .roll)
|
||||||
/savegif
|
/savegif
|
||||||
/savepasta
|
*/savepasta
|
||||||
/sendhelp
|
*/truth
|
||||||
/truth
|
|
||||||
|
|
||||||
TODO: In the future I'd like to change to a single `/save {type}` command
|
TODO: In the future I'd like to change to a single `/save {type}` command
|
||||||
|
|
||||||
Dot-Extension Commands:
|
Dot-Extension Commands: [* means updated]
|
||||||
.gif
|
*.gif
|
||||||
.pasta
|
*.pasta
|
||||||
.request
|
*.request
|
||||||
.spongebob
|
*.spongebob
|
||||||
.strain
|
*.strain
|
||||||
.weather
|
|
204
main.js
204
main.js
@ -0,0 +1,204 @@
|
|||||||
|
/* eslint-disable no-case-declarations */
|
||||||
|
/* eslint-disable indent */
|
||||||
|
// dotenv for handling environment variables
|
||||||
|
const dotenv = require('dotenv');
|
||||||
|
dotenv.config();
|
||||||
|
const token = process.env.TOKEN;
|
||||||
|
|
||||||
|
// Discord.JS
|
||||||
|
const { Client, Intents } = require('discord.js');
|
||||||
|
const client = new Client({
|
||||||
|
intents: [
|
||||||
|
'GUILDS',
|
||||||
|
'GUILD_MESSAGES',
|
||||||
|
'GUILD_MESSAGE_REACTIONS',
|
||||||
|
'DIRECT_MESSAGES',
|
||||||
|
'DIRECT_MESSAGE_REACTIONS',
|
||||||
|
],
|
||||||
|
partials: [
|
||||||
|
'CHANNEL',
|
||||||
|
'MESSAGE',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const { MessageActionRow, MessageButton } = require('discord.js');
|
||||||
|
|
||||||
|
// Various imports
|
||||||
|
const fn = require('./functions.js');
|
||||||
|
const config = require('./config.json');
|
||||||
|
const strings = require('./strings.json');
|
||||||
|
|
||||||
|
client.once('ready', () => {
|
||||||
|
fn.collections.slashCommands(client);
|
||||||
|
fn.collections.dotCommands(client);
|
||||||
|
fn.collections.setvalidCommands(client);
|
||||||
|
fn.download.gifs(client);
|
||||||
|
fn.download.pastas(client);
|
||||||
|
fn.download.joints(client);
|
||||||
|
fn.download.requests(client);
|
||||||
|
fn.download.strains(client);
|
||||||
|
console.log('Ready!');
|
||||||
|
client.channels.fetch(config.devChannelId).then(channel => {
|
||||||
|
channel.send(`I'm ready! ${new Date().toISOString()}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// slash-commands
|
||||||
|
client.on('interactionCreate', async interaction => {
|
||||||
|
if (interaction.isCommand()) {
|
||||||
|
if (config.isDev) {
|
||||||
|
console.log(interaction);
|
||||||
|
}
|
||||||
|
const { commandName } = interaction;
|
||||||
|
|
||||||
|
if (client.slashCommands.has(commandName)) {
|
||||||
|
client.slashCommands.get(commandName).execute(interaction);
|
||||||
|
} else {
|
||||||
|
interaction.reply('Sorry, I don\'t have access to that command.');
|
||||||
|
console.error('Slash command attempted to run but not found: ' + commandName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isButton()) {
|
||||||
|
if (interaction.user.id != strings.temp.gifUserId) return;
|
||||||
|
// Get some meta info from strings
|
||||||
|
const index = strings.temp.gifIndex;
|
||||||
|
const limit = strings.temp.gifLimit;
|
||||||
|
let newIndex;
|
||||||
|
const buttonId = interaction.component.customId;
|
||||||
|
switch (buttonId) {
|
||||||
|
case 'prevGif':
|
||||||
|
newIndex = index - 1;
|
||||||
|
strings.temp.gifIndex = newIndex;
|
||||||
|
// If we're leaving the last GIF, enable the Next GIF button
|
||||||
|
if (index == limit) {
|
||||||
|
// Re-Send Previous GIF button
|
||||||
|
const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY');
|
||||||
|
// Re-Send Confirm GIF Button
|
||||||
|
const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY');
|
||||||
|
// Enable Next GIF Button
|
||||||
|
const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY');
|
||||||
|
// Re-Send Cancel Button
|
||||||
|
const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER');
|
||||||
|
// Put all the above into an ActionRow to be sent as a component of the reply
|
||||||
|
const row = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton);
|
||||||
|
|
||||||
|
interaction.update({ content: strings.temp.gifs[newIndex].embed_url, components: [row] });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If we're going into the first GIF, disable the Previous GIF button
|
||||||
|
if (newIndex == 0) {
|
||||||
|
// Disable Previous GIF button
|
||||||
|
const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled();
|
||||||
|
// Re-Send Confirm GIF Button
|
||||||
|
const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY');
|
||||||
|
// Re-Send Next GIF Button
|
||||||
|
const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY');
|
||||||
|
// Re-Send Cancel Button
|
||||||
|
const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Canceled').setStyle('DANGER');
|
||||||
|
// Put all the above into an ActionRow to be sent as a component of the reply
|
||||||
|
const row = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton);
|
||||||
|
|
||||||
|
interaction.update({ content: strings.temp.gifs[newIndex].embed_url, components: [row] });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
interaction.update(strings.temp.gifs[newIndex].embed_url);
|
||||||
|
break;
|
||||||
|
case 'confirmGif':
|
||||||
|
interaction.update({ content: 'GIF Confirmed, what should I save it as?\n(*don\'t* include the .gif)', components: [] });
|
||||||
|
const collector = fn.collect.gifName(interaction);
|
||||||
|
collector.on('collect', m => {
|
||||||
|
const gifData = {
|
||||||
|
name: m.content.toLowerCase(),
|
||||||
|
embed_url: strings.temp.gifs[strings.temp.gifIndex].embed_url,
|
||||||
|
};
|
||||||
|
fn.upload.gif(gifData, client);
|
||||||
|
m.reply(`I've saved the GIF as ${gifData.name}.gif`);
|
||||||
|
fn.download.gifs(interaction.client);
|
||||||
|
collector.stop('success');
|
||||||
|
});
|
||||||
|
fn.download.gifs(interaction.client);
|
||||||
|
break;
|
||||||
|
case 'nextGif':
|
||||||
|
newIndex = index + 1;
|
||||||
|
strings.temp.gifIndex = newIndex;
|
||||||
|
// If we're leaving the first GIF, enable the Previous GIF button
|
||||||
|
if (index == 0) {
|
||||||
|
// Enable Previous GIF button
|
||||||
|
const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled(false);
|
||||||
|
// Re-Send Confirm GIF Button
|
||||||
|
const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY');
|
||||||
|
// Re-Send Next GIF Button
|
||||||
|
const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY');
|
||||||
|
// Re-Send Cancel Button
|
||||||
|
const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER');
|
||||||
|
// Put all the above into an ActionRow to be sent as a component of the reply
|
||||||
|
const row = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton);
|
||||||
|
|
||||||
|
interaction.update({ content: strings.temp.gifs[newIndex].embed_url, components: [row] });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If we're going into the last GIF, disable the Next GIF button
|
||||||
|
if (newIndex == strings.temp.gifLimit) {
|
||||||
|
// Re-Send Previous GIF button
|
||||||
|
const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY');
|
||||||
|
// Re-Send Confirm GIF Button
|
||||||
|
const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY');
|
||||||
|
// Disable Next GIF Button
|
||||||
|
const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY').setDisabled();
|
||||||
|
// Re-Send Cancel Button
|
||||||
|
const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Canceled').setStyle('DANGER');
|
||||||
|
// Put all the above into an ActionRow to be sent as a component of the reply
|
||||||
|
const row = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton);
|
||||||
|
|
||||||
|
interaction.update({ content: strings.temp.gifs[newIndex].embed_url, components: [row] });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
interaction.update(strings.temp.gifs[newIndex].embed_url);
|
||||||
|
break;
|
||||||
|
case 'cancelGif':
|
||||||
|
// Previous GIF button
|
||||||
|
const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled();
|
||||||
|
// Confirm GIF Button
|
||||||
|
const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY').setDisabled();
|
||||||
|
// Next GIF Button
|
||||||
|
const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY').setDisabled();
|
||||||
|
// Cancel Button
|
||||||
|
const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Canceled').setStyle('DANGER');
|
||||||
|
// Put all the above into an ActionRow to be sent as a component of the reply
|
||||||
|
const row = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton);
|
||||||
|
interaction.component.setDisabled(true);
|
||||||
|
|
||||||
|
interaction.update({ content: 'Canceled.', components: [row] });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// dot-commands
|
||||||
|
client.on('messageCreate', message => {
|
||||||
|
// Some basic checking to prevent running unnecessary code
|
||||||
|
if (message.author.bot) return;
|
||||||
|
|
||||||
|
// Wildcard Responses, will respond if any message contains the trigger word(s), excluding self-messages
|
||||||
|
if (message.content.includes('big') && message.content.includes('doinks')) message.reply('gang.');
|
||||||
|
if (message.content.includes('ligma')) message.reply('ligma balls, goteem');
|
||||||
|
|
||||||
|
const commandData = fn.dot.getCommandData(message);
|
||||||
|
console.log(commandData);
|
||||||
|
if (commandData.isValid && commandData.isCommand) {
|
||||||
|
try {
|
||||||
|
client.dotCommands.get(commandData.command).execute(message, commandData);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
message.reply('There was an error trying to execute that command.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login(token);
|
@ -10,7 +10,8 @@
|
|||||||
"discord-api-types": "^0.22.0",
|
"discord-api-types": "^0.22.0",
|
||||||
"discord.js": "^13.1.0",
|
"discord.js": "^13.1.0",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"pg": "^8.6.0",
|
"fuzzy-search": "^3.2.1",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
"tenorjs": "^1.0.8"
|
"tenorjs": "^1.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
17
slash-commands/closereq.js
Normal file
17
slash-commands/closereq.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('closereq')
|
||||||
|
.setDescription('Close a request by ID, retrieved from /requests')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('requestid')
|
||||||
|
.setDescription('The ID of the request you\'d like to close.')
|
||||||
|
.setRequired(true)),
|
||||||
|
async execute(interaction) {
|
||||||
|
const requestId = interaction.options.getString('requestid');
|
||||||
|
fn.closeRequest(requestId, interaction.client);
|
||||||
|
interaction.reply(`Request #${requestId} closed.`);
|
||||||
|
},
|
||||||
|
};
|
33
slash-commands/gifs.js
Normal file
33
slash-commands/gifs.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const { config } = require('dotenv');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('gifs')
|
||||||
|
.setDescription('Get a list of currently saved GIFs.'),
|
||||||
|
async execute(interaction) {
|
||||||
|
if (!interaction.client.gifs) {
|
||||||
|
interaction.reply('For some reason I don\'t have access to the collection of gifs. Sorry about that!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const gifsMap = interaction.client.gifs.map(e => {
|
||||||
|
return {
|
||||||
|
id: e.id,
|
||||||
|
name: e.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const commandData = {
|
||||||
|
gifs: [],
|
||||||
|
command: 'gifs',
|
||||||
|
author: interaction.user.tag,
|
||||||
|
};
|
||||||
|
for (const row of gifsMap) {
|
||||||
|
commandData.gifs.push({
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
interaction.reply(fn.embeds.gifs(commandData));
|
||||||
|
},
|
||||||
|
};
|
30
slash-commands/help.js
Normal file
30
slash-commands/help.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('help')
|
||||||
|
.setDescription('Send the help page.')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('location')
|
||||||
|
.setDescription('Send help in this channel or in DMs?')
|
||||||
|
.setRequired(true)
|
||||||
|
.addChoice('Here', 'channel')
|
||||||
|
.addChoice('DMs', 'dm')),
|
||||||
|
async execute(interaction) {
|
||||||
|
switch (interaction.options.getString('location')) {
|
||||||
|
case 'channel':
|
||||||
|
await interaction.reply(fn.embeds.help(interaction));
|
||||||
|
break;
|
||||||
|
case 'dm':
|
||||||
|
await interaction.user.createDM().then(channel => {
|
||||||
|
channel.send(fn.embeds.help(interaction));
|
||||||
|
interaction.reply('I\'ve sent you a copy of my help page.');
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interaction.reply('There was an error, please try again.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
17
slash-commands/joint.js
Normal file
17
slash-commands/joint.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
const { emoji } = require('../strings.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('joint')
|
||||||
|
.setDescription('Replies with a random cannabis-related quote.'),
|
||||||
|
async execute(interaction) {
|
||||||
|
let joints = [];
|
||||||
|
for (const entry of interaction.client.joints.map(joint => joint.content)) {
|
||||||
|
joints.push(entry);
|
||||||
|
}
|
||||||
|
const randIndex = Math.floor(Math.random() * joints.length);
|
||||||
|
interaction.reply(`${joints[randIndex]} ${emoji.joint}`);
|
||||||
|
},
|
||||||
|
};
|
15
slash-commands/joints.js
Normal file
15
slash-commands/joints.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('joints')
|
||||||
|
.setDescription('Send a list of all the /joint phrases.'),
|
||||||
|
async execute(interaction) {
|
||||||
|
let joints = [];
|
||||||
|
interaction.client.joints.map(e => {
|
||||||
|
joints.push(e.content);
|
||||||
|
});
|
||||||
|
interaction.reply('Here are all the `.joint` phrases I have saved:\n\n' + joints.join('\n'));
|
||||||
|
},
|
||||||
|
};
|
11
slash-commands/lenny.js
Normal file
11
slash-commands/lenny.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('lenny')
|
||||||
|
.setDescription('( ͡° ͜ʖ ͡°)'),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.channel.send('( ͡° ͜ʖ ͡°)');
|
||||||
|
},
|
||||||
|
};
|
33
slash-commands/pastas.js
Normal file
33
slash-commands/pastas.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const { config } = require('dotenv');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('pastas')
|
||||||
|
.setDescription('Get a list of currently saved copypastas.'),
|
||||||
|
async execute(interaction) {
|
||||||
|
if (!interaction.client.pastas) {
|
||||||
|
interaction.reply('For some reason I don\'t have access to the collection of copypastas. Sorry about that!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const commandData = {
|
||||||
|
author: interaction.user.tag,
|
||||||
|
command: interaction.commandName,
|
||||||
|
pastas: [],
|
||||||
|
};
|
||||||
|
const pastasMap = interaction.client.pastas.map(e => {
|
||||||
|
return {
|
||||||
|
id: e.id,
|
||||||
|
name: e.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
for (const row of pastasMap) {
|
||||||
|
commandData.pastas.push({
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
interaction.reply(fn.embeds.pastas(commandData));
|
||||||
|
},
|
||||||
|
};
|
11
slash-commands/ping.js
Normal file
11
slash-commands/ping.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('ping')
|
||||||
|
.setDescription('Check that the bot is alive and responding.'),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.reply('Pong!');
|
||||||
|
},
|
||||||
|
};
|
20
slash-commands/reload.js
Normal file
20
slash-commands/reload.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('reload')
|
||||||
|
.setDescription('Reload all saved content, useful if saving something fails.'),
|
||||||
|
async execute(interaction) {
|
||||||
|
const { client } = interaction;
|
||||||
|
fn.collections.slashCommands(client);
|
||||||
|
fn.collections.dotCommands(client);
|
||||||
|
fn.collections.setvalidCommands(client);
|
||||||
|
fn.download.gifs(client);
|
||||||
|
fn.download.pastas(client);
|
||||||
|
fn.download.joints(client);
|
||||||
|
fn.download.requests(client);
|
||||||
|
fn.download.strains(client);
|
||||||
|
interaction.reply('Reloaded!');
|
||||||
|
},
|
||||||
|
};
|
31
slash-commands/requests.js
Normal file
31
slash-commands/requests.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const { config } = require('dotenv');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('requests')
|
||||||
|
.setDescription('Get a list of Active requests from the database'),
|
||||||
|
async execute(interaction) {
|
||||||
|
const commandData = {
|
||||||
|
author: interaction.user.tag,
|
||||||
|
command: interaction.commandName,
|
||||||
|
requests: [],
|
||||||
|
};
|
||||||
|
const requestsMap = interaction.client.requests.map(e => {
|
||||||
|
return {
|
||||||
|
id: e.id,
|
||||||
|
author: e.author,
|
||||||
|
request: e.request,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
for (const row of requestsMap) {
|
||||||
|
commandData.requests.push({
|
||||||
|
id: row.id,
|
||||||
|
author: row.author,
|
||||||
|
request: row.request,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
interaction.reply(fn.embeds.requests(commandData));
|
||||||
|
},
|
||||||
|
};
|
56
slash-commands/savegif.js
Normal file
56
slash-commands/savegif.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
const tenor = require('tenorjs').client({
|
||||||
|
'Key': process.env.tenorAPIKey, // https://tenor.com/developer/keyregistration
|
||||||
|
'Filter': 'off', // "off", "low", "medium", "high", not case sensitive
|
||||||
|
'Locale': 'en_US',
|
||||||
|
'MediaFilter': 'minimal',
|
||||||
|
'DateFormat': 'D/MM/YYYY - H:mm:ss A',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const { MessageActionRow, MessageButton } = require('discord.js');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
const strings = require('../strings.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('savegif')
|
||||||
|
.setDescription('Search Tenor for a GIF to save')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('query')
|
||||||
|
.setDescription('Search Query')
|
||||||
|
.setRequired(true)),
|
||||||
|
async execute(interaction) {
|
||||||
|
// Previous GIF button
|
||||||
|
const prevButton = new MessageButton().setCustomId('prevGif').setLabel('Previous GIF').setStyle('SECONDARY').setDisabled(true);
|
||||||
|
// Confirm GIF Button
|
||||||
|
const confirmButton = new MessageButton().setCustomId('confirmGif').setLabel('Confirm').setStyle('PRIMARY');
|
||||||
|
// Next GIF Button
|
||||||
|
const nextButton = new MessageButton().setCustomId('nextGif').setLabel('Next GIF').setStyle('SECONDARY');
|
||||||
|
// Cancel Button
|
||||||
|
const cancelButton = new MessageButton().setCustomId('cancelGif').setLabel('Cancel').setStyle('DANGER');
|
||||||
|
// Put all the above into an ActionRow to be sent as a component of the reply
|
||||||
|
const actionRow = new MessageActionRow().addComponents(prevButton, confirmButton, nextButton, cancelButton);
|
||||||
|
|
||||||
|
// Get the query
|
||||||
|
const query = interaction.options.getString('query');
|
||||||
|
|
||||||
|
// Search Tenor for the GIF
|
||||||
|
tenor.Search.Query(query, '10').then(res => {
|
||||||
|
strings.temp.gifs = [];
|
||||||
|
strings.temp.gifIndex = 0;
|
||||||
|
strings.temp.gifLimit = res.length - 1;
|
||||||
|
strings.temp.gifUserId = interaction.user.id;
|
||||||
|
|
||||||
|
if (res[0] == undefined) {
|
||||||
|
interaction.reply('Sorry I was unable to find a GIF of ' + query);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const row of res) {
|
||||||
|
strings.temp.gifs.push({
|
||||||
|
embed_url: row.media[0].gif.url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
interaction.reply({ content: strings.temp.gifs[0].embed_url, components: [actionRow] });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
17
slash-commands/savejoint.js
Normal file
17
slash-commands/savejoint.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
const { emoji } = require('../strings.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('savejoint')
|
||||||
|
.setDescription('Save a phrase for /joint!')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('joint-content')
|
||||||
|
.setDescription('What is the phrase?')
|
||||||
|
.setRequired(true)),
|
||||||
|
async execute(interaction) {
|
||||||
|
fn.upload.joint(interaction.options.getString('joint-content'), interaction.client);
|
||||||
|
interaction.reply(`The joint has been rolled${emoji.joint}`);
|
||||||
|
},
|
||||||
|
};
|
24
slash-commands/savepasta.js
Normal file
24
slash-commands/savepasta.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('savepasta')
|
||||||
|
.setDescription('Save a copypasta!')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('pasta-name')
|
||||||
|
.setDescription('What should the name of the copypasta be?')
|
||||||
|
.setRequired(true))
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('pasta-content')
|
||||||
|
.setDescription('What is the content of the copypasta?')
|
||||||
|
.setRequired(true)),
|
||||||
|
async execute(interaction) {
|
||||||
|
const pastaData = {
|
||||||
|
name: interaction.options.getString('pasta-name'),
|
||||||
|
content: interaction.options.getString('pasta-content'),
|
||||||
|
};
|
||||||
|
fn.upload.pasta(pastaData, interaction.client);
|
||||||
|
interaction.reply(`The copypasta has been saved as ${pastaData.name}.pasta`);
|
||||||
|
},
|
||||||
|
};
|
11
slash-commands/template
Normal file
11
slash-commands/template
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('')
|
||||||
|
.setDescription(''),
|
||||||
|
async execute(interaction) {
|
||||||
|
await
|
||||||
|
},
|
||||||
|
};
|
11
slash-commands/truth.js
Normal file
11
slash-commands/truth.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const { SlashCommandBuilder } = require('@discordjs/builders');
|
||||||
|
const fn = require('../functions.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('truth')
|
||||||
|
.setDescription('The truth about the MHallihan Flight Simulator'),
|
||||||
|
async execute(interaction) {
|
||||||
|
await interaction.reply('https://www.twitch.tv/hochmania/clip/EsteemedSlickDootStinkyCheese-hncmP8aIP8_WQb_a?filter=clips&range=all&sort=time');
|
||||||
|
},
|
||||||
|
};
|
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"weed": [
|
|
||||||
"It's dangerous to go alone, take this",
|
|
||||||
"Dave's not here, man",
|
|
||||||
"I was gonna clean my room, but then I got high",
|
|
||||||
"When in doubt, smoke it out",
|
|
||||||
"I smoke two joints before I smoke two joints, and then I smoke two more",
|
|
||||||
"Today's forecast is cloudy with a chance of munchies",
|
|
||||||
"You're gonna be doing a lot of doobie rollin' when you're living in a ran down by the river!",
|
|
||||||
"You'll have plenty of time to live in a van down by the river... when you're living in a van down by the river!",
|
|
||||||
"Roll, roll, roll my joint, pick out the seeds and stems"
|
|
||||||
],
|
|
||||||
"emoji": {
|
|
||||||
"joint": "<:joint:862082955902976000>",
|
|
||||||
"next": "⏭️",
|
|
||||||
"previous": "⏮️",
|
|
||||||
"confirm": "☑️",
|
|
||||||
"cancel": "❌"
|
|
||||||
}
|
|
||||||
}
|
|
18
strings.json
Normal file
18
strings.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"help": {
|
||||||
|
"description": "Hi there! Thanks for checking out NodBot. NodBot is used in two distinct ways: with 'Slash Commands' (/help), and with 'Dot Commands' (nod.gif). The two types will be outlined below, along with usage examples.",
|
||||||
|
"slash": "Slash Commands always begin with a / and a menu will pop up to help complete the commands.",
|
||||||
|
"dot": "Dot Commands have the command at the end of the message, for example to search for a gif of 'nod', type 'nod.gif'"
|
||||||
|
},
|
||||||
|
"emoji": {
|
||||||
|
"joint": "<:joint:862082955902976000>",
|
||||||
|
"next": "⏭️",
|
||||||
|
"previous": "⏮️",
|
||||||
|
"confirm": "☑️",
|
||||||
|
"cancel": "❌"
|
||||||
|
},
|
||||||
|
"urls": {
|
||||||
|
"avatar": "https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128"
|
||||||
|
},
|
||||||
|
"temp": {}
|
||||||
|
}
|
23
testing.txt
Normal file
23
testing.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[ NodBot v3 Testing Procedure ]
|
||||||
|
|
||||||
|
/ping
|
||||||
|
/help [Here | DMs]
|
||||||
|
/gifs
|
||||||
|
/pastas
|
||||||
|
/joints
|
||||||
|
/requests
|
||||||
|
/savegif
|
||||||
|
/savepasta
|
||||||
|
/savejoint
|
||||||
|
[ ! CREATE MANUAL ENTRIES IN ALL 4 DBs ! ]
|
||||||
|
/reload
|
||||||
|
|
||||||
|
/joint
|
||||||
|
/truth
|
||||||
|
|
||||||
|
nod.gif
|
||||||
|
random.gif
|
||||||
|
bush.pasta
|
||||||
|
random.request
|
||||||
|
|
||||||
|
[ TODO: Error handling testing ]
|
Loading…
Reference in New Issue
Block a user