Transitioned all Misc, audio, Selmer Specific, admin, anime/manga, and inventory commands to Slash Command format. The RSS and reactionrole commands are still broken and all game commands are still in message format due to compications

This commit is contained in:
ION606
2022-09-27 16:45:50 -04:00
parent a190a250a6
commit e1002d748d
45 changed files with 1951 additions and 1058 deletions
+1
View File
@@ -1,5 +1,6 @@
node_modules
config.json
backup.json
*.env
*.sqlite
*.txt
+7 -4
View File
@@ -1,7 +1,7 @@
module.exports = {
name: 'extracredit',
description: "Selmer Bot Dm's you for some *AHEM* extra credit",
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
let dm;
let num = Math.floor(Math.random() * 10);
@@ -41,7 +41,10 @@ module.exports = {
break;
}
let ID = message.member.id;
message.client.users.fetch(ID).then(user => user.send(dm));
}
// let ID = interaction.user.id;
// message.client.users.fetch(ID).then(user => user.send(dm));
interaction.user.send(dm);
interaction.reply({content: "Extra Credit sent 😉", ephemeral: true});
},
options: []
}
+9 -18
View File
@@ -1,24 +1,15 @@
module.exports = {
name: 'arrow',
description: 'Engage in a trademarked activity and throw an arrow at a trash can',
async execute(message, args, Discord, Client, bot) {
let counter = 0;
async execute(interaction, Discord, Client, bot) {
arrow = '>';
while (true) {
arrow = '-' + arrow;
message.channel.send(arrow);
await message.channel.messages.fetch({limit: 1}).then(messages => {
message.channel.bulkDelete(messages);
});
counter ++;
if (counter >= 5) {
message.channel.messages.fetch({limit: 1}).then(messages => {
message.channel.bulkDelete(messages);
});
arrow = arrow + '🗑️';
message.channel.send(arrow);
break;
}
await interaction.reply(arrow);
for (let i = 0; i < 5; i++) {
arrow = '-' + arrow
await interaction.editReply(arrow);
}
}
arrow = arrow + '🗑️';
await interaction.editReply(arrow);
}, options: []
}
+3 -3
View File
@@ -1,7 +1,7 @@
module.exports = {
name: "profile",
description: "Posts a description of Monsieur Sleemer himself",
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
const newEmbed = new Discord.MessageEmbed()
.setColor('#002eff')
.setTitle('My professional resume')
@@ -14,6 +14,6 @@ module.exports = {
{name: '\t__Epithet 2__', value: "_There is no god, only logic_"}
);
message.channel.send({ embeds: [newEmbed] });
}
interaction.reply({ embeds: [newEmbed] });
}, options: []
}
+4 -3
View File
@@ -1,7 +1,7 @@
module.exports = {
name: 'quotes',
description: "A public version of Extra Credit",
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
let dm;
let num = Math.floor(Math.random() * 10);
@@ -41,6 +41,7 @@ module.exports = {
break;
}
message.channel.send(dm);
}
interaction.reply(dm);
},
options: []
}
+5 -5
View File
@@ -1,9 +1,9 @@
const { MessageEmbed, MessageActionRow, MessageButton, Interaction } = require('discord.js');
module.exports = {
name: 'code',
description: 'See where Selmer bot\'s code is stored! (you can also use _!repo_)',
execute(message, args, Discord, Client, bot) {
name: 'repo',
description: 'See where Selmer bot\'s code is stored!',
execute(interaction, Discord, Client, bot) {
const embd = new MessageEmbed()
.setAuthor({ name: "Selmer Bot", url: bot.inviteLink, iconURL: bot.user.displayAvatarURL() })
.setThumbnail("https://github.com/ION606/selmer-bot-website/blob/main/assets/Selmer-icon.png?raw=true") // .setThumbnail('https://repository-images.githubusercontent.com/460670550/43932b23-d795-4334-838f-f33ee8f795c4')
@@ -27,6 +27,6 @@ module.exports = {
.setCustomId("sbtutorial")
]);
message.reply({ embeds: [embd], components: [row] })
}
interaction.reply({ embeds: [embd], components: [row] });
}, options: []
}
@@ -3,17 +3,17 @@ const { MessageActionRow, MessageButton, MessageEmbed, Interaction } = require('
//Intro, setup/logging, Econ, Moderation, anime/manga, games, Selmer Specific, Misc, DMS/Premium
const tutoText = [
"__**Hello, and welcome to the Selmer Bot tutorial!**__\nIn this tutorial, I will walk you through the various commands and features of Selmer Bot!\n\nTo progress to the next page, click the right arrow at the bottom of this message.\nTo go back to the previous page, click the left arrow",
"__**SETUP AND LOGGING**__\nSet up your server to take full advantage of Selmer Bot's features, this includes moderation logging, custom welcome messages, calendar event pings and more!\n_Note: Most of these commands are only available to the server owner_\n\n__***COMMANDS***__\n!setup help welcome, !setup help logs, !setup help announcement, !setup welcome_channel, !setup welcome_message, !setup keep_logs, !setup log_channel, !setup log_severity, !setup announcement_channel, !setup announcement_role",
"__**ECONOMY**__\nThese commands have to do with the inventory and currency system Selmer Bot uses, although I should note that as of now Selmer Coin holds no IRL value ;-;\n\n__***COMMANDS***__\n!inventory, !buy, !sell, !shop, !work, !rank, !balance",
"__**MODERATION**__\nI mean....\n\n***__COMMANDS__***\n!help admin, !warn, !mute, !unmute, !kick, !ban, !unban, !lock, !unlock, !serverlock",
"__**AMIME AND MANGA**__\nGet info on your favorite Anime or Manga as a stat-sheet, a fancy embed, or have Selmer Bot describe it to you!\n\n__***COMMANDS***__\n!asearch, !msearch",
"__**GAMES**__\nAt the moment Selmer Bot only offers two games: Trivia and Tic Tac Toe. Both games can be played with other people, but only Trivia can be played solo. Selmer Bot also has a battle game where you can use weapons, potions, attack and defend, but this is still in beta\n\n__***COMMANDS***__\n!help game, !game battle !game tictactoe, !game trivia, !game equip, !game status, !game hp, !game classes, !game quit",
"__**SELMER SPECIFIC**__\nThese commands will probably be found nowhere else!\nThese include quotes (For legal reasons I have to state they aren't real quotes, mostly), as well as varius other things I based on good old Selmer\n\n__***COMMANDS***__\n!arrow, !extracredit, !tuto, !profile, !quotes",
"__**MISCELLANEOUS**__\nThese are the commands that are not really in any of the other categories. Don't be fooled, these are actually some of the most useful commands Selmer Bot has to offer. From playing music to web scraping to memes, I'm sure Selmer Bot has what you're looking for!\n\n__***COMMANDS***__\n!help, !kareoke, !link, !meme, !pickupline, !audio, !react, !scrape, !stocks, !crypto",
"__**DM COMMANDS**__\nThese commands will only work in DM's. All these commands will only work with Selmer Bot Premium (it's on the next page).\nThese features include Reminders (AKA a calendar) and Selmer Bot's own chat AI!\n\n__***COMMANDS***__\n!chat, !startconvo, !endconvo, !premium",
"__**SELMER BOT PREMIUM**__\nUse an AI chat, complete with semi-accurate IRL data, have Selmer Bot remind you of events with an easy-to-use interface and even a clickable calendar on the Selmer Bot website (_www.selmerbot.com_)\n\n__***COMMANDS***__\n!premium, !premium buy, !premium manage, !reminders",
"__**Thank you for completing the Selmer Bot Tutorial!**__\n\nTry out Selmer Bot's features, play the games and most importantly, have fun!\n\n-The Selmer Bot Team AKA ION606"
"__**Hello, and welcome to the Selmer Bot tutorial**__\nIn this tutorial, I will walk you through the various commands and features of Selmer Bot\n\nTo progress to the next page, click the right arrow at the bottom of this message.\nTo go back to the previous page, click the left arrow",
"__**SETUP AND LOGGING**__\nSet up your server to take full advantage of Selmer Bot's features, this includes moderation logging, custom welcome messages, calendar event pings and more\n_Note: Most of these commands are only available to the server owner_\n\n__***COMMANDS***__\nsetup",
"__**ECONOMY**__\nThese commands have to do with the inventory and currency system Selmer Bot uses, although I should note that as of now Selmer Coin holds no IRL value ;-;\n\n__***COMMANDS***__\ninventory, buy, sell, shop, work, rank, balance",
"__**MODERATION**__\nI mean....\n\n***__COMMANDS__***\nhelp admin, warn, mute, unmute, kick, ban, unban, lock, unlock, serverlock\n\n__***NOTE:***__\nThe user needs to have either _kick_ or _ban_ permissions to use these",
"__**AMIME AND MANGA**__\nGet info on your favorite Anime or Manga as a stat-sheet, a fancy embed, or have Selmer Bot describe it to you\n__***COMMANDS***__\nasearch, msearch",
"__**GAMES**__\nAt the moment Selmer Bot offers three games: Trivia, Tic Tac Toe, and Minesweeper. Both Trivia and Tic Tac Toe can be played with other people. Trivia and Minesweeper can also be played solo. Selmer Bot also has a battle game where you can use weapons, potions, attack and defend, but this is still in beta\n\n__***COMMANDS***__\nhelp game, game battle game tictactoe, game trivia, game equip, game status, game hp, game classes, game quit\n\n__**NOTE**__\nDue to how complicated this feature is, it will not be migrated to slash commands for now",
"__**SELMER SPECIFIC**__\nThese commands will probably be found nowhere else\nThese include quotes (For legal reasons I have to state they aren't real quotes, mostly), as well as varius other things I based on good old Selmer\n\n__***COMMANDS***__\narrow, extracredit, tuto, profile, quotes",
"__**MISCELLANEOUS**__\nThese are the commands that are not really in any of the other categories. Don't be fooled, these are actually some of the most useful commands Selmer Bot has to offer. From playing music to web scraping to memes, I'm sure Selmer Bot has what you're looking for\n\n__***COMMANDS***__\nhelp, kareoke, link, meme, pickupline, audio, react, scrape, stocks, crypto",
"__**DM COMMANDS**__\nThese commands will only work in DM's. All these commands will only work with Selmer Bot Premium (it's on the next page).\nThese features include Reminders (AKA a calendar) and Selmer Bot's own chat AI\n\n__***COMMANDS***__\nchat, startconvo, endconvo, premium",
"__**SELMER BOT PREMIUM**__\nUse an AI chat, complete with semi-accurate IRL data, have Selmer Bot remind you of events with an easy-to-use interface and even a clickable calendar on the Selmer Bot website (_www.selmerbot.com_)\n\n__***COMMANDS***__\npremium, premium buy, premium manage, reminders",
"__**Thank you for completing the Selmer Bot Tutorial**__\n\nTry out Selmer Bot's features, play the games and most importantly, have fun\n\n-The Selmer Bot Team AKA ION606"
];
//If the page number == 0 and refered == false, then interaction will be a Message
@@ -76,7 +76,8 @@ function postEmbd(bot, interaction, page, refered) {
module.exports = {
name: 'tuto',
description: 'An introduction command to Selmer Bot',
async execute(message, args, Discord, Client, bot) {
postEmbd(bot, message, 0, false);
}, postEmbd
async execute(interaction, Discord, Client, bot) {
postEmbd(bot, interaction, 0, false);
}, postEmbd,
options: []
}
+63
View File
@@ -0,0 +1,63 @@
const fs = require('fs');
const {Buffer} = require('buffer');
function mapToObj(map){
const obj = {}
for (let [k,v] of map) {
obj[k] = v
}
return obj
}
function objToMap(obj) {
const m = new Map();
for (i in obj) {
m.set(i, obj[i]);
}
return m;
}
async function backupLists(bot, IDM) {
try {
var backups = {}
backups.locked = mapToObj(bot.lockedChannels);
const bts = JSON.stringify({ "backups": backups });
if (IDM) {
fs.writeFile('commands/admin/backup.json', bts, 'utf8', (err) => {
// error checking
if(err) throw err;
console.log("New data added: " + bts);
process.exit(0);
});
} else {
process.env.backupLists = bts;
process.exit(0);
}
} catch (err) {
console.error(err);
exit(-1);
}
}
async function loadBotBackups(bot, IDM) {
try {
if (IDM) {
const botBackups = require('./backup.json').backups;
bot.lockedChannels = objToMap(botBackups.locked);
} else {
bot.lockedChannels = objToMap(JSON.parse(botBackups.locked));
}
} catch (err) {
console.error(err);
bot.lockedChannels = new Map();
const a = new Map();
}
}
module.exports = { backupLists, loadBotBackups }
+14 -11
View File
@@ -1,28 +1,31 @@
const { checkRole } = require('./verify.js');
const { Constants } = require('discord.js');
module.exports = {
name: 'lock',
description: 'Lock a channel',
execute(message, args, Discord, Client, bot) {
const guild = bot.guilds.cache.get(message.guild.id);
execute(interaction, Discord, Client, bot) {
const arg = interaction.options.data[0];
const guild = bot.guilds.cache.get(interaction.guildId);
if (!checkRole(bot, guild, message.author.id)) { return message.reply('Insufficient Permissions!'); }
if (!checkRole(bot, guild, interaction.user.id)) { return interaction.reply('Insufficient Permissions!'); }
var channel;
if (args[0]) {
channel = guild.channels.cache.find(channel => channel.name.toLowerCase() === args[0]);
if (arg) {
channel = arg.channel;
} else {
channel = message.channel;
channel = interaction.channel;
}
if (!channel) { return message.reply("This channel does not exist!"); }
channel.permissionOverwrites.edit(message.guild.roles.everyone.id, {
let role = interaction.guild.roles.cache.find(r => r.name === "@everyone");
channel.permissionOverwrites.edit(role.id, {
VIEW_CHANNEL: true,
SEND_MESSAGES: false,
READ_MESSAGE_HISTORY: true,
ATTACH_FILES: false
});
}
interaction.reply(`${channel} has been locked!`);
},
options: [{name: 'channel', description: 'The channel to lock (defaults to current channel)', type: Constants.ApplicationCommandOptionTypes.CHANNEL, required: false}]
}
+31 -26
View File
@@ -1,6 +1,7 @@
//@ts-check
const { log, SEVCODES } = require('../log.js');
const { checkRole } = require('./verify.js');
const { Constants } = require('discord.js');
function modHelp() {
@@ -15,7 +16,7 @@ function kick(guild, user) {
}
async function toggle_ban(guild, message, args, ban, reason) {
async function toggle_ban(guild, interaction, args, ban, reason) {
if (ban) {
guild.members.ban(args);
@@ -27,7 +28,7 @@ async function toggle_ban(guild, message, args, ban, reason) {
i++
}
return new Promise((resolve, reject) => {
message.guild.bans.fetch().then((users) => {
interaction.guild.bans.fetch().then((users) => {
const userObj = users.filter((u) => {
return (`${u.user.username}#${u.user.discriminator}` == user);
}).first();
@@ -51,29 +52,29 @@ async function toggle_ban(guild, message, args, ban, reason) {
}
function toggle_mute(bot, guild, command, message, user, reason, mute) {
function toggle_mute(bot, guild, command, interaction, user, reason, mute) {
const mutedRole = guild.roles.cache.find((role) => role.name.toLowerCase() === 'muted');
const guser = guild.members.cache.get(user.id);
// if there is no `Muted` role, send an error
if (!mutedRole) { return message.channel.send('There is no "muted" role on this server. Please create one then try again'); }
if (!mutedRole) { return interaction.reply('There is no "muted" role on this server. Please create one then try again'); }
if (mute) {
if (guser.roles.cache.get(mutedRole.id) == undefined) {
guser.roles.add(mutedRole);
log(bot, message, command, user, reason, SEVCODES.low);
} else { message.reply("This user is already muted!"); }
log(bot, interaction, command, user, reason, SEVCODES.low);
} else { interaction.reply("This user is already muted!"); }
} else {
if (guser.roles.cache.get(mutedRole.id) != undefined) {
guser.roles.remove(mutedRole);
log(bot, message, command, user, reason, SEVCODES.none);
} else { message.reply("This user is not muted!"); }
log(bot, interaction, command, user, reason, SEVCODES.none);
} else { interaction.reply("This user is not muted!"); }
}
/*
NOTE: use the following function for a "time out" type thing?
setTimeout(() => {
target.roles.remove(mutedRole); // remove the role
}, <time>)
}, <time>)
*/
}
@@ -94,43 +95,47 @@ function timeOut(bot, user, message, args, command, reason) {
}
function moderation_handler(bot, message, args, command) {
const guild = message.guild;
function moderation_handler(bot, interaction, command) {
const guild = interaction.guild;
//Verify
if (!checkRole(bot, guild, message.author.id)) { return message.reply('Insufficient Permission!'); }
if (!checkRole(bot, guild, interaction.user.id)) { return interaction.reply('Insufficient Permission!'); }
let mentioned = message.mentions.users.first();
if (mentioned && mentioned.id == message.author.id) { return message.reply(`You can't ${command} yourself!`); }
const mentioned = interaction.options.data.filter((arg) => { return (arg.name == 'user'); })[0].user;
if (mentioned && mentioned.id == interaction.user.id) { return interaction.reply(`You can't ${command} yourself!`); }
const reason = args.slice(1).join(' ');
const reasonInit = interaction.options.data.filter((arg) => { return (arg.name == 'reason'); })[0];
const reason = (reasonInit) ? reasonInit.value : "None";
if (message.mentions.members.first() && (message.mentions.members.first().roles.highest.position > message.guild.members.resolve(bot.user).roles.highest.position)) {
return message.reply("I'm not high enough in the role hierarchy to do that!\n_To raise my place, go to **Server Settings -> Roles** then drag me up!_");
const user = guild.members.resolve(mentioned.id);
if (user && (user.roles.highest.position > guild.members.resolve(bot.user).roles.highest.position)) {
return interaction.reply("I'm not high enough in the role hierarchy to do that!\n_To raise my place, go to **Server Settings -> Roles** then drag me up!_");
}
if (command != 'unban' && !mentioned || !reason) { return message.channel.send(`Please use the following format: _!<command> <user> <reason>`); }
if (command == 'unban' && !args[0] && !reason) { return message.channel.send("Please use the following format: _!unban <user_tag>#<user_discriminator> <reason>\nExample: _!unban John#1122_"); }
// if (command != 'unban' && !mentioned || !reason) { return message.channel.send(`Please use the following format: _!<command> <user> <reason>`); }
// if (command == 'unban' && !args[0] && !reason) { return message.channel.send("Please use the following format: _!unban <user_tag>#<user_discriminator> <reason>\nExample: _!unban John#1122_"); }
// if (command == 'ban' && guild.members.cache.get(mentioned.id).bannable) { message.reply("This user is not bannable!"); } //Broken
// if (command == 'ban' && !message.guild.members.cache.get(mentioned.id)) { message.reply("This user is not in the server"); }
switch (command) {
case 'kick': kick(guild, mentioned);
log(bot, message, command, mentioned, reason, SEVCODES.medium);
log(bot, interaction, command, mentioned, reason, SEVCODES.medium);
break;
case 'ban': toggle_ban(guild, message, mentioned, true, reason);
log(bot, message, command, mentioned, reason, SEVCODES.high);
case 'ban': toggle_ban(guild, interaction, mentioned, true, reason);
log(bot, interaction, command, mentioned, reason, SEVCODES.high);
break;
//Leave the then() catch() thing, it needs to be async
case 'unban': toggle_ban(guild, message, args, false, reason).then((user) => { log(bot, message, command, user, reason, SEVCODES.none)}).catch((note) => { message.reply(note); });
case 'unban': toggle_ban(guild, interaction, false, reason).then((user) => { log(bot, interaction, command, user, reason, SEVCODES.none)}).catch((note) => { interaction.reply(note); });
break;
case 'mute': toggle_mute(bot, guild, command, message, mentioned, reason, true);
case 'mute': toggle_mute(bot, guild, command, interaction, mentioned, reason, true);
break;
case 'unmute': toggle_mute(bot, guild, command, message, mentioned, reason, true);
case 'unmute': toggle_mute(bot, guild, command, interaction, mentioned, reason, true);
break;
// case 'timeout': timeOut(bot, mentioned, message, args, command, reason);
@@ -143,5 +148,5 @@ function moderation_handler(bot, message, args, command) {
module.exports = {
name: 'moderation',
moderation_handler, modHelp
moderation_handler, modHelp,
}
+32 -14
View File
@@ -1,18 +1,36 @@
module.exports = {
name: 'serverLock',
description: 'Lock ***ALL CHANNELS*** for everyone with the "everyone" role - ***SERVER OWNER ONLY. FOR EMERGENCY USE ONLY***',
execute(message, args, Discord, Client, bot) {
const guild = bot.guilds.cache.get(message.guild.id);
name: 'serverlock',
description: 'Lock ALL CHANNELS for everyone with the "everyone" role - SERVER OWNER ONLY!',
execute(interaction, Discord, Client, bot) {
if (interaction.guild.ownerId != interaction.user.id) { return interaction.reply('Insufficient Permissions!'); }
if (guild.ownerId != message.author.id) { return message.reply('Insufficient Permissions!'); }
const role = interaction.guild.roles.cache.find(r => r.name === "@everyone");
const arr = [];
message.guild.channels.cache.forEach(ch => {
channel.permissionOverwrites.edit(message.guild.roles.everyone.id, {
VIEW_CHANNEL: false,
SEND_MESSAGES: false,
READ_MESSAGE_HISTORY: false,
ATTACH_FILES: false
});
interaction.guild.channels.cache.forEach(channel => {
if (channel.permissionsFor(role).has("SEND_MESSAGES")) {
channel.permissionOverwrites.edit(role.id, {
VIEW_CHANNEL: true,
SEND_MESSAGES: false,
READ_MESSAGE_HISTORY: true,
ATTACH_FILES: false
});
//Maybe add the message to the array to be edited/deleted after unlock
if (channel.type == 'GUILD_TEXT') {
channel.send(`***CHANNEL LOCKED BY ${interaction.user}***`);
}
arr.push(channel.id);
}
});
}
}
bot.lockedChannels.set(interaction.guildId, arr);
interaction.reply(`***SERVER LOCKED BY ${interaction.user}***`);
}, options: []
}
// interaction.reply(```diff
// - SERVER LOCKED
// ```);
+27 -16
View File
@@ -1,21 +1,32 @@
// const { checkRole } = require('./verify.js');
//Maybe add a list to selmer Bot that adds the channels when locking
module.exports = {
name: 'serverunlock',
description: 'unlocks the channels locked using /serverlock',
execute(interaction, Discord, Client, bot) {
const guild = bot.guilds.cache.get(interaction.guildId);
const role = interaction.guild.roles.cache.find(r => r.name === "@everyone");
// module.exports = {
// name: 'serverUnlock',
// description: 'unlocks ***ALL CHANNELS*** for everyone except the those with the "Selmer Bot Commands" role',
// execute(message, args, Discord, Client, bot) {
// const guild = bot.guilds.cache.get(message.guild.id);
// if (!checkRole(bot, guild, message.author.id)) { return message.reply('Insufficient Permissions!'); }
if (interaction.guild.ownerId != interaction.user.id) { return interaction.reply('Insufficient Permissions!'); }
// if (!checkRole(bot, guild, message.author.id)) { return message.reply('Insufficient Permissions!'); }
const channelIds = bot.lockedChannels.get(interaction.guildId);
// message.guild.channels.cache.forEach(ch => {
// channel.permissionOverwrites.edit(message.guild.roles.everyone.id, {
// VIEW_CHANNEL: true,
// SEND_MESSAGES: false,
// READ_MESSAGE_HISTORY: false,
// ATTACH_FILES: false
// });
// });
// }
// }
if (!channelIds) { return interaction.reply("No channels to unlock..."); }
channelIds.forEach(id => {
const channel = guild.channels.cache.get(id);
channel.permissionOverwrites.edit(role.id, {
VIEW_CHANNEL: true,
SEND_MESSAGES: true,
READ_MESSAGE_HISTORY: true,
ATTACH_FILES: true
});
});
bot.lockedChannels.set(interaction.guildId, []);
interaction.reply(`Channels unlocked by ${interaction.user}`);
},
options: []
}
+98 -91
View File
@@ -1,5 +1,6 @@
//@ts-check
const { MongoClient, ServerApiVersion } = require('mongodb');
const { Constants } = require('discord.js');
const { CreateNewCollection } = require("../db/econ");
@@ -10,108 +11,104 @@ async function setWelcomeChannel(dbo, message, channelname) {
async function execute(bot, message, args, command, Discord, mongouri, items, xp_collection) {
const server = message.guild.id;
const owner = message.guild.members.cache.get(message.guild.ownerId);
async function execute(interaction, Discord, Client, bot) {
const server = interaction.guildId;
const owner = interaction.guild.members.cache.get(interaction.guild.ownerId);
const args = interaction.options.data;
if (message.author.id != message.guild.ownerId) {
return message.reply('Only the server owner can do this!');
if (interaction.user.id != interaction.guild.ownerId) {
return interaction.reply({content: 'Only the server owner can do this!', ephemeral: true});
}
// // @ts-ignore
// const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
// if (client.writeConcern || client.writeConcern) {
// client.close();
// return message.reply("Something went wrong with the database, please try again later and contact support if this problem persists!");
// }
bot.mongoconnection.then(async (client) => {
// if (err) { return console.log(err); }
try {
//Initialize
CreateNewCollection(message, client, server, owner.user.id);
//Initialize
CreateNewCollection(interaction, client, server, owner.user.id);
const db = client.db(server);
const dbo = db.collection('SETUP');
const db = client.db(server);
const dbo = db.collection('SETUP');
//Chose the appropriate command
command = args[0];
if (args.length < 1) { return interaction.reply({content: "Please chose a valid option", ephemeral: true}); }
if (!command) {
message.channel.send('Please use the following format _!setup help <welcome, logs>_');
} else if (command == 'welcome_channel') {
if (args.length != 2) { return message.reply('The command format is _!setup welcome_channel <channel name>_'); }
// setWelcomeChannel(dbo, message, args[1]);
const channel = message.guild.channels.cache.find(ch => ch.name === args[1]);
if (!channel) { return message.reply('The specified channel does not exist!'); }
for (let i = 0; i < args.length; i++) {
try {
const command = args[i].name;
dbo.updateOne({welcomechannel: {$exists: true}}, {$set: {welcomechannel: `${channel.id}`}});
message.reply(`Set ${channel} as the new welcome channel`)
} else if (command == 'welcome_message') {
if (args.length < 2) { return message.reply('The command format is _!setup welcome\\_message_\nUse _{sn}_ to insert the server name, _{un}_ to insert the user name, and _{ut}_ to insert the user tag\nExample: _!setup welcome\\_message Welcome to {sn} Sir {un}#{ut}_'); }
let msg = "";
for (let i = 1; i < args.length; i ++ ) {
msg += args[i] + ' ';
// if (!command) {
// interaction.reply('Please use the following format _!setup help <welcome, logs>_');
// } else
if (command == 'welcome_channel') {
// if (args.length != 2) { return interaction.reply('The command format is _!setup welcome_channel <channel name>_'); }
// setWelcomeChannel(dbo, message, args[1]);
const channel = args[i].channel;
dbo.updateOne({welcomechannel: {$exists: true}}, {$set: {welcomechannel: `${channel.id}`}});
interaction.reply({content: `Set ${channel} as the new welcome channel`, ephemeral: true})
} else if (command == 'welcome_message') {
// if (args.length < 2) { return interaction.reply('The command format is _!setup welcome\\_message_\nUse _{sn}_ to insert the server name, _{un}_ to insert the user name, and _{ut}_ to insert the user tag\nExample: _!setup welcome\\_message Welcome to {sn} Sir {un}#{ut}_'); }
const msg = args[i].value;
if (msg.length > 30 || msg.length < 1) { return interaction.reply({content: 'Please specify a welcome message between 0 and 30 characters!', ephemeral: true}); }
dbo.updateOne({welcomemessage: {$exists: true}}, {$set: {welcomemessage: msg}})
} else if (command == 'keep_logs') {
let keeplogs = args[i].value;
dbo.updateOne({ _id: 'LOG'}, {$set: {keepLogs: keeplogs}});
interaction.reply({content: `Toggled log keeping to ${keeplogs}. Please use _!setup log_channel_ to choose the log channel`, ephemeral: true});
} else if (command == 'log_channel') {
// if (args.length != 2) { return message.reply('Please specify a parameter\nExample: _!setup log\\_channel true_'); }
const channel = args[i].channel;
if (!channel) { return interaction.reply({content: 'The specified channel does not exist!', ephemeral: true}); }
dbo.updateOne({_id: 'LOG'}, {$set: {logchannel: `${channel.id}`}});
interaction.reply({content: `Made ${channel} the new Selmer Bot Logs channel!`, ephemeral: true});
} else if (command == 'log_severity') {
const tier = args[i].value;
const l = ['none', 'low', 'medium', 'high'];
if (!l.includes(tier)) { return interaction.reply({content: "Please select an existing tier ('none', 'low', 'medium', 'high')", ephemeral: true}); }
dbo.updateOne({_id: 'LOG'}, {$set: {severity: tier}})
interaction.reply({content: `Severity updated to ${tier}`, ephemeral: true});
} else if (command == 'announcement_role') {
const role = args[i].value;
// if (message.mentions.roles.first() == undefined) {
// return message.reply("Please mention a role (_!setup announcement\\_role **@role**_)\n_Note: Selmer Bot does NOT ping the @everyone role_");
// }
// const role = message.mentions.roles.first().id;
dbo.updateOne({_id: 'announcement'}, { $set: { 'role': role.id } });
interaction.reply({content: `Role updated to ${role}`, ephemeral: true});
} else if (command == "announcement_channel") {
const channel = args[i].channel;
if (!channel) { return interaction.reply({content: 'The specified channel does not exist!', ephemeral: true}); }
dbo.updateOne({_id: 'announcement'}, { $set: { 'channel': channel.id } });
} else {
interaction.reply({content: "Please chose a valid option", ephemeral: true});
}
/* Made obsolete by the change to Slash Commands
if (msg.length > 30) { return message.reply('Please specify a welcome message under 30 characters!'); }
dbo.updateOne({welcomemessage: {$exists: true}}, {$set: {welcomemessage: msg}})
} else if (command == 'keep_logs') {
if (args.length != 2) { return message.reply('Please specify a parameter\nExample: _!setup keep\\_logs true'); }
else if (command == 'help') {
let temp;
const subcat = args[i].value;
if (args[1] == 'welcome') {
temp = 'Use _/setup welcome\\_channel [channel name]_ to set the welcome channel and _/setup welcome\\_message [message]_ to set a welcome message/\n';
} else if (args[1] == 'logs') {
temp = 'To enable logging, use the command _/setup keep\\_logs true_ and _/setup log\\_channel_ [channel name] to set the logging channel/\n';
temp += 'Use _/setup keep\\_logs false_ to disable logging and _/setup log\\_severity [none, low, medium, high]_ to set the threshold\n';
temp += '__Severities:__\n*none* - unmute, unban\n*low* - mute\n*medium* - kick\n*high* - ban\nEvery tier also includes all notifs for ***higher*** tiers (AKA _/setup log\\_severity none_ will log everything from every severity)\n';
} else if (args[1] == 'announcement') {
temp = "To pick the announcement channel, use _/setup announcement\\_channel_\nTo pick the announcement role, use _/setup announcement\\_role_";
} else { temp = 'Use _/setup Please use the following format: _/setup help [welcome, logs, announcement]_\nExample: _/setup help welcome_'; }
let keeplogs = false;
if (args[1] == 'true') { keeplogs = true; }
dbo.updateOne({ _id: 'LOG'}, {$set: {keepLogs: keeplogs}});
message.reply(`Toggled log keeping to ${keeplogs}. Please use _!setup log_channel_ to choose the log channel`);
} else if (command == 'log_channel') {
if (args.length != 2) { return message.reply('Please specify a parameter\nExample: _!setup log\\_channel true_'); }
const channel = message.guild.channels.cache.find(ch => ch.name === args[1]);
if (!channel) { return message.reply('The specified channel does not exist!'); }
dbo.updateOne({_id: 'LOG'}, {$set: {logchannel: `${channel.id}`}});
message.reply(`Made ${channel} the new Selmer Bot Logs channel!`);
} else if (command == 'log_severity') {
const tier = args[1];
const l = ['none', 'low', 'medium', 'high'];
if (!l.includes(tier)) { return message.reply("Please select an existing tier ('none', 'low', 'medium', 'high')"); }
dbo.updateOne({_id: 'LOG'}, {$set: {severity: tier}})
message.reply("Severity updated!");
} else if (command == 'announcement_role') {
if (message.mentions.roles.first() == undefined) {
return message.reply("Please mention a role (_!setup announcement\\_role **@role**_)\n_Note: Selmer Bot does NOT ping the @everyone role_");
}
const role = message.mentions.roles.first().id;
dbo.updateOne({_id: 'announcement'}, { $set: { 'role': role } });
message.reply("Role updated!");
} else if (command == "announcement_channel") {
const channel = message.guild.channels.cache.find(ch => ch.name === args[1]);
if (!channel) { return message.reply('The specified channel does not exist!'); }
dbo.updateOne({_id: 'announcement'}, { $set: { 'channel': channel.id } });
interaction.reply({content: temp, ephemeral: true});
}*/
} catch (err) {
console.error(err);
}
else if (command == 'help') {
let temp;
if (args[1] == 'welcome') {
temp = 'Use _!setup welcome\\_channel [channel name]_ to set the welcome channel and _!setup welcome\\_message [message]_ to set a welcome message!\n';
} else if (args[1] == 'logs') {
temp = 'To enable logging, use the command _!setup keep\\_logs true_ and _!setup log\\_channel_ [channel name] to set the logging channel!\n';
temp += 'Use _!setup keep\\_logs false_ to disable logging and _!setup log\\_severity [none, low, medium, high]_ to set the threshold\n';
temp += '__Severities:__\n*none* - unmute, unban\n*low* - mute\n*medium* - kick\n*high* - ban\nEvery tier also includes all notifs for ***higher*** tiers (AKA _!setup log\\_severity none_ will log everything from every severity)\n';
} else if (args[1] == 'announcement') {
temp = "To pick the announcement channel, use _!setup announcement\\_channel_\nTo pick the announcement role, use _!setup announcement\\_role_";
} else { temp = 'Use _!setup Please use the following format: _!setup help [welcome, logs, announcement]_\nExample: _!setup help welcome_'; }
message.reply(temp);
}
} catch (err) {
console.error(err);
}
});
}
@@ -123,5 +120,15 @@ async function execute(bot, message, args, command, Discord, mongouri, items, xp
module.exports = {
name: 'setup',
description: 'Set up server features',
execute
execute,
options: [
{name: 'welcome_channel', description: 'Sets the channel for welcome messages', type: Constants.ApplicationCommandOptionTypes.CHANNEL },
{name: 'welcome_message', description: 'Sets the welcome message, Use {un} for username, {ut} for user tag and {sn} for server name', type: Constants.ApplicationCommandOptionTypes.STRING },
{name: 'keep_logs', description: 'Toggles logging', type: Constants.ApplicationCommandOptionTypes.BOOLEAN },
{name: 'log_channel', description: 'Sets the logging channel', type: Constants.ApplicationCommandOptionTypes.CHANNEL },
{name: 'log_severity', description: 'Sets the logging Severity (logs this/lower tiers)', type: Constants.ApplicationCommandOptionTypes.STRING, choices: [{name: 'none', value: 'none'}, {name: 'low', value: 'low'}, {name: 'medium', value: 'medium'}, {name: 'high', value: 'high'}] },
{name: 'announcement_role', description: 'Sets the role to be pinged for reminders', type: Constants.ApplicationCommandOptionTypes.ROLE},
{name: 'announcement_channel', description: 'Sets the channel for reminders', type: Constants.ApplicationCommandOptionTypes.CHANNEL}
// {name: 'help', description: 'gets help with setup commands', type: Constants.ApplicationCommandOptionTypes.STRING, choices: [{name: 'welcome', value: 'welcome'}, {name: 'logs', value: 'logs'}, {name: 'announcement', value: 'announcement'}]}
]
}
+14 -9
View File
@@ -1,28 +1,33 @@
const { checkRole } = require('./verify.js');
const { Constants } = require('discord.js');
module.exports = {
name: 'unlock',
description: 'Unlock a channel',
execute(message, args, Discord, Client, bot) {
const guild = bot.guilds.cache.get(message.guild.id);
execute(interaction, Discord, Client, bot) {
const arg = interaction.options.data[0];
const guild = bot.guilds.cache.get(interaction.guildId);
if (!checkRole(bot, guild, message.author.id)) { return message.reply('Insufficient Permissions!'); }
if (!checkRole(bot, guild, interaction.user.id)) { return message.reply('Insufficient Permissions!'); }
var channel;
if (args[0]) {
channel = guild.channels.cache.find(channel => channel.name.toLowerCase() === args[0]);
if (arg) {
channel = arg.channel;
} else {
channel = message.channel;
channel = interaction.channel;
}
if (!channel) { return message.reply("This channel does not exist!"); }
let role = interaction.guild.roles.cache.find(r => r.name === "@everyone");
channel.permissionOverwrites.edit(message.guild.roles.everyone.id, {
channel.permissionOverwrites.edit(role.id, {
VIEW_CHANNEL: true,
SEND_MESSAGES: true,
READ_MESSAGE_HISTORY: true,
ATTACH_FILES: true
});
}
interaction.reply(`${channel} has been unlocked!`);
},
options: [{name: 'channel', description: 'The channel to unlock (defaults to current channel)', type: Constants.ApplicationCommandOptionTypes.CHANNEL, required: false}]
}
+38 -28
View File
@@ -1,24 +1,27 @@
const { Constants } = require('discord.js');
const scraper = require('mal-scraper');
module.exports = {
name: 'asearch',
description: 'Selmer bot gives you info on an anime',
async execute(message, args, Discord, Client, bot) {
if (args.length < 1) { return message.reply("Please specify an anime!"); }
let name = "";
if (args.length > 1) {
let i = 0;
while (i < args.length && args[i] != '~fancy' && args[i] != '~summary' && args[i] != '~stats') {
name += args[i] + " ";
i++;
}
} else { name = args[0]; }
async execute(interaction, Discord, Client, bot) {
if (args[args.length - 1] != '~fancy' && args[args.length - 1] != '~summary' && args[args.length - 1] != '~stats') { args.push('~stats'); }
const args = interaction.options.data;
const name = args.filter((arg) => { return (arg.name == 'anime'); })[0].value;
var style;
if (args.length > 1) {
style = args.filter((arg) => { return (arg.name == 'style'); })[0].value;
}
else { style = "stats"; }
//Maybe change it to "this anime movie" if there is only 1 episode?
//When set to true, getInfoFromName.getBestMatch did not, in fact, return the best results
scraper.getInfoFromName(name, false).then((data) => {
try {
if (args[args.length - 1] == '~stats') {
try { console.log(data);
if (style == 'stats') {
const newEmbed = new Discord.MessageEmbed()
.setColor('#002eff')
.setTitle(data.title)
@@ -28,40 +31,47 @@ module.exports = {
.addFields(
{name: 'Genres:', value: data.genres.join(", ")},
{name: 'Score:', value: data.score},
{name: 'Episode:', value: data.episodes}
{name: 'Episode:', value: data.episodes},
{name: "Date Aired/Premiered", value: data.premiered || data.aired}
).setURL(data.trailer);
message.channel.send({ embeds: [newEmbed] });
} else if (args[args.length - 1] == '~fancy') {
let temp = `The ${data.genres.join(", ")} anime _${data.title}_ first aired on ${data.premiered}`;
interaction.reply({ embeds: [newEmbed] });
} else if (style == 'fancy') {
let temp = `The ${data.genres.join(", ")} anime _${data.title}_ first aired on ${data.premiered || data.aired}`;
if (data.aired) { temp += `. This anime ran for ${data.aired} for a total of ${data.episodes} episodes.`}
else { temp += ` and is still airing with ${data.episodes} so far!`}
temp += ` This anime has a score of ${data.score} and is ${data.popularity} on MyAnimeList!\n`;
temp += `You can see a trailer for ${data.title} here: ${data.trailer}`;
temp += `\n\n(to see a summary of the anime, use '${bot.prefix}asearch <anime name> ~summary')`;
temp += `You can see a trailer for ${data.title} ***[here](${data.trailer})***`;
// temp += `\n\n(to see a summary of the anime, use '${bot.prefix}asearch <anime name> summary')`;
message.channel.send({ embeds: [new Discord.MessageEmbed().setImage(data.picture)]});
message.channel.send(temp);
} else if (args[args.length - 1] == '~summary') {
interaction.reply({ embeds: [new Discord.MessageEmbed().setImage(data.picture).setDescription(temp)] });
// message.channel.send(temp);
} else if (style == 'summary') {
let temp = data.synopsis;
message.channel.send(temp);
interaction.reply(temp);
} else {
message.reply(`Unknown command, try using the format '${bot.prefix}asearch <anime name> [~stats or ~fancy or ~summary]`);
interaction.reply(`Unknown command, try using the format '/asearch <anime name> [stats or fancy or summary]`);
}
} catch (err) {
if (err.message.indexOf('MessageEmbed field values must be non-empty strings') != -1) {
message.reply(`Insufficient information on website!\nThe page can be found here: ${data.url}`);
interaction.reply(`Insufficient information on website!\nThe page can be found here: ${data.url}`);
} else {
message.reply("Uh oh, an unknown error occured, click the ✅ to report this!");
const m = interaction.reply("Uh oh, an unknown error occured, click the ✅ to report this!");
const { addComplaintButton } = require('../dev only/submitcomplaint');
addComplaintButton(bot, message);
m.then((msg) => {
addComplaintButton(bot, msg);
});
}
console.log(err);
}
});
}
},
options: [
{name: 'anime', description: 'The name of the anime', type: Constants.ApplicationCommandOptionTypes.STRING, required: true},
{name: 'style', description: 'stats or fancy or summary (defaults to stats)', type: Constants.ApplicationCommandOptionTypes.STRING, required: false, choices: [ { name: 'stats', value: 'stats' }, { name: 'fancy', value: 'fancy' }, {name: 'summary', value: 'summary'} ] }
]
}
+27 -24
View File
@@ -1,23 +1,21 @@
const { Constants } = require('discord.js');
const scraper = require('mal-scraper');
const search = scraper.search;
const type = "manga";
module.exports = {
name: 'msearch',
description: 'Selmer bot gives you info on a manga',
async execute(message, args, Discord, Client, bot) {
if (args.length < 1) { return message.reply("Please specify a manga!"); }
if (args[args.length - 1] != '~fancy' && args[args.length - 1] != '~summary' && args[args.length - 1] != '~stats') { args.push('~stats'); }
let name = "";
if (args.length > 1) {
let i = 0;
while (i < args.length && args[i] != '~fancy' && args[i] != '~summary' && args[i] != '~stats') {
name += args[i] + " ";
i++;
}
}
async execute(interaction, Discord, Client, bot) {
const args = interaction.options.data;
const name = args.filter((arg) => { return (arg.name == 'manga'); })[0].value;
var style;
let cmd = args[args.length - 1];
if (args.length > 1) {
style = args.filter((arg) => { return (arg.name == 'style'); })[0].value;
}
else { style = "stats"; }
try {
search.search(type, {
@@ -25,7 +23,7 @@ module.exports = {
term: name
}).then((data1) => {
let data = data1[0];
if (cmd == "~stats") {
if (style == "stats") {
const newEmbed = new Discord.MessageEmbed()
.setColor('#ff9900')
.setTitle(data.title)
@@ -38,32 +36,37 @@ module.exports = {
{name: 'Volumes:', value: data.vols}
);
message.channel.send({ embeds: [newEmbed] });
} else if (cmd == "~fancy") {
interaction.reply({ embeds: [newEmbed] });
} else if (style == "fancy") {
let temp = `The ${data.type} _${data.title}_ currently has ${data.vols} volumes with ${data.nbChapters} chapters, `;
temp += `running from _${data.startDate.replace(/-/g, "/")}_ to _${data.endDate.replace(/-/g, "/")}_, and has a score of ${data.score} on MyAnimeList!\n`;
temp += `You can read more about _${data.title}_ at ${data.url}`;
message.channel.send(temp);
} else if (cmd == "~summary") {
interaction.reply(temp);
} else if (style == "summary") {
//Remove the "read more." at the end
let temp = data.shortDescription.slice(0, -10);
temp += ` _read more at_ ${data.url}`;
return message.channel.send(temp);
return interaction.reply(temp);
} else {
message.reply(`Unknown command, try using the format '${bot.prefix}msearch <manga name> [~stats or ~fancy or ~summary]`);
interaction.reply(`Unknown command, try using the format '${bot.prefix}msearch <manga name> [stats or fancy or summary]`);
}
});
} catch (err) {
if (err.message.indexOf('MessageEmbed field values must be non-empty strings') != -1) {
message.reply(`Insufficient information on website!\nThe page can be found here: ${data.url}`);
interaction.reply(`Insufficient information on website!\nThe page can be found here: ${data.url}`);
} else {
message.reply("Uh oh, an unknown error occured, click the ✅ to report this!");
const m = interaction.reply("Uh oh, an unknown error occured, click the ✅ to report this!");
const { addComplaintButton } = require('../dev only/submitcomplaint');
addComplaintButton(bot, message);
m.then((msg) => {
addComplaintButton(bot, msg);
});
}
console.log(err);
}
}
},
options: [{name: 'manga', description: 'The name of the manga', type: Constants.ApplicationCommandOptionTypes.STRING, required: true}, {name: 'style', description: 'stats or fancy or summary (defaults to stats)', type: Constants.ApplicationCommandOptionTypes.STRING, required: false, choices: [ { name: 'stats', value: 'stats' }, { name: 'fancy', value: 'fancy' }, {name: 'summary', value: 'summary'} ] }]
}
+43
View File
@@ -0,0 +1,43 @@
const axios = require('axios');
/**
* @param {String} purl
* @returns {Promise<Array<String>>}
*
* @example
* const purls = getPlaylistUrls(url);
* purls.then((urls) => { console.log(urls); });
*/
async function getPlaylistUrls(bot, purl, isPremium) {
const gApiKey = bot.youtubeAPIKey;
const numSongs = (isPremium) ? 20 : 10;
return new Promise(async (resolve, reject) => {
try {
const pid = (purl.split("list=")[1]).replace("&feature=share", "");
await axios.get(`https://www.googleapis.com/youtube/v3/playlistItems`, {
params: {
part: 'id,snippet',
maxResults: numSongs,
playlistId: pid,
key: gApiKey
}
})
.then((result) => {
const l = [];
result.data.items.forEach((vid, ind) => {
const vurl = `https://www.youtube.com/watch?v=${vid.snippet.resourceId.videoId}`
const pvurl = `https://www.youtube.com/watch?v=${vid.snippet.resourceId.videoId}&list=${pid}&index=${ind+1}`
l.push({video_url: vurl, in_playlist_url: pvurl});
});
resolve(l);
}).catch((err) => { reject(err.message); });
} catch (err) {
reject(err.message);
}
});
}
module.exports = { getPlaylistUrls }
+600
View File
@@ -0,0 +1,600 @@
// const { joinVoiceChannel, createAudioResource } = require('@discordjs/voice');
const { VoiceConnectionStatus, AudioPlayerStatus, createAudioPlayer, StreamType, joinVoiceChannel, createAudioResource, getVoiceConnection } = require('@discordjs/voice');
const { MessageActionRow, MessageButton, MessageEmbed, Constants } = require('discord.js');
const play = require('play-dl');
const { getPlaylistUrls } = require('./addPlaylist.js');
const { verPremium } = require('../premium/verifyPremium.js');
// Note: Unsure of what this does , but may be related to the play-dl lib (my notes are inconsistent)
// play.authorization();
async function playMusic(bot, interaction, channelId, url, isPlaylist) {
return new Promise(async (resolve, reject) => {
const channel = bot.channels.cache.get(channelId);
const connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
});
connection.on(VoiceConnectionStatus.Ready, () => {
// console.log('Connected to the voice channel!');
});
try {
let stream;
let yt_info;
if (url.startsWith("https://")) {
if (!url.startsWith("https://www.youtube.com/") &&
!url.startsWith("https://music.youtube.com/") && !url.startsWith("https://youtu.be/")) {
if (!isPlaylist) {
interaction.reply("This is not a valid YouTube URL").catch((err) => {
console.log(err.message);
interaction.reply("Uh oh, an error has occured!");
});
reject();
return;
}
}
yt_info = await play.video_info(url);
// let stream = await play.stream_from_info(yt_info)
stream = await play.stream(url);
// console.log("Playing from a URL!");
} else {
yt_info = await play.search(url, {
limit: 1
});
stream = await play.stream(yt_info[0].url);
yt_info = await play.video_info(yt_info[0].url);
}
let resource = createAudioResource(stream.stream, {
inputType: stream.type
})
// let audio = "em.mp3";
// let resource = createAudioResource(join(__dirname, audio));
const data = bot.audioData.get(channel.guild.id);
if (data && data[1]) {
//[player, [queue Array]]
data[1].push({yt_info: yt_info, resource: resource});
bot.audioData.set(interaction.guildId, data);
if (!isPlaylist) {
interaction.reply(`_"${yt_info.video_details.title}" added to queue!_`).catch((err) => {
channel.send("Uh oh, there's been a Discord API error!");
console.log(err);
reject();
});
}
} else {
const player = createAudioPlayer();
connection.subscribe(player);
bot.audioData.set(interaction.guildId, [player, new Array(), null]);
player.play(resource);
player.on(AudioPlayerStatus.Playing, () => {
//Check maybe?
});
player.on(AudioPlayerStatus.Idle, () => {
//TODO find away to trigger the "stop" event here
// playNext(interaction, bot);
// pause_start_stop(interaction, bot);
});
playStopEmbed(bot, interaction, yt_info, false, true);
}
resolve(true);
} catch (err) {
if (!isPlaylist) {
console.log(err);
interaction.reply("Uh Oh, there's been an error!").catch((err) => { console.log(err); })
}
reject();
}
});
}
async function playStopEmbed(bot, interaction, yt_info, stopped, message = null) {
if (stopped) {
var em = interaction.message.embeds[0];
rows = [];
em.description = new String;
em.description = 'IS NOW STOPPED';
interaction.update({embeds: [em], components: rows});
} else {
const author = {
name: "Selmer Bot",
url: "",
iconURL: bot.user.displayAvatarURL()
}
const newEmbed = new MessageEmbed()
.setColor('#0F00F0')
.setTitle(`${yt_info.video_details.title}`)
.setAuthor(author)
.setDescription('IS NOW PLAYING')
.setURL(yt_info.video_details.url)
.setThumbnail(yt_info.video_details.thumbnails[0].url);
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId('PAUSE')
.setLabel('⏸️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('STOP')
.setLabel('⏹️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('SKIP')
.setLabel('⏭️')
.setStyle('SECONDARY')
);
if (message) {
if (interaction) {
const m = interaction.channel.send({ embeds: [newEmbed], components: [row] });
m.then((msg) => {
const data = bot.audioData.get(interaction.guildId);
data[2] = msg.id;
bot.audioData.set(interaction.guildId, data);
});
} else {
const m = message.reply({ embeds: [newEmbed], components: [row] });
m.then((msg) => {
const data = bot.audioData.get(message.guild.id);
data[2] = msg.id;
bot.audioData.set(message.guild.id, data);
});
}
} else {
interaction.update({embeds: [newEmbed], components: [row]});
}
}
}
function pause_start_stop(interaction, bot, message = null, command = null) {
try {
var player, em, guildId;
if (interaction) { guildId = interaction.guildId }
else { guildId = message.guild.id; }
const data = bot.audioData.get(guildId);
if (!data) {
var em = interaction.message.embeds[0];
em.description = new String;
em.description = 'IS NOW STOPPED';
return interaction.message.edit({ components: [], embeds: [em]});
}
if (interaction) {
player = data[0];
command = interaction.customId.toLowerCase();
em = interaction.message.embeds[0];
} else {
player = data[0];
em = message.embeds[0];
}
var rows = [new MessageActionRow()];
if (command == "pause") {
rows[0].addComponents(
new MessageButton()
.setCustomId('RESUME')
.setLabel('▶️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('STOP')
.setLabel('⏹️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('SKIP')
.setLabel('⏭️')
.setStyle('SECONDARY')
);
em.description = 'IS NOW PAUSED';
player.pause();
} else if (command == "resume") {
rows[0].addComponents(
new MessageButton()
.setCustomId('PAUSE')
.setLabel('⏸️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('STOP')
.setLabel('⏹️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('SKIP')
.setLabel('⏭️')
.setStyle('SECONDARY')
);
em.description = 'IS NOW PLAYING';
player.unpause();
} else if (command == "stop") {
playStopEmbed(bot, interaction, null, true);
const connection = getVoiceConnection(interaction.guild.id);
player.stop();
//Remove everything from queue
bot.audioData.delete(interaction.guildId);
if (connection) { connection.destroy(); }
return;
}
if (interaction) { interaction.update({embeds: [em], components: rows}); }
else {
const data = bot.audioData.get(guildId);
// var msg = message.channel.messages.cache.get(data[2]);
const newEmbed = message.embeds[0];
newEmbed.description = "Has been deferred";
message.edit({ embeds: [ newEmbed ], components: []});
const m = message.reply({embeds: [em], components: rows});
m.then((msg) => {
const data = bot.audioData.get(message.guild.id);
data[2] = msg.id;
bot.audioData.set(message.guild.id, data);
});
}
} catch (e) {
console.log(e);
rows = [];
em.description = new String('IS NOW STOPPED');
interaction.update({embeds: [em], components: rows});
}
}
function playNext(interaction, bot, message = null) {
// https://discordjs.guide/voice/audio-player.html#taking-action-within-the-error-handler
//Setup data[1] = {info: yt_info, resource: resource}
var guildId;
if (message != null) { guildId = message.guild.id; }
else { guildId = interaction.guildId; }
let data = bot.audioData.get(guildId);
if (!data) { return interaction.followUp("Audio queue empty!"); }
const player = data[0];
//Check if the queue is empty
if (data[1].length <= 0) {
player.stop();
bot.audioData.delete(guildId);
if (message) { return true; }
else { return playStopEmbed(bot, interaction, null, true); }
}
const resource = data[1][0].resource;
const yt_info = data[1][0].yt_info;
player.stop();
//Play the thing
player.play(resource);
//remove the song from queue
delete data[1][0];
data[1] = data[1].filter(n => n);
bot.audioData.set(guildId, data);
//Add the embed
var msg = message;
if (!message) {
msg = interaction.message;
interaction.update({ embeds: [ new MessageEmbed(interaction.message.embeds[0]).setDescription("IS NOW STOPPED") ], components: []});
}
playStopEmbed(bot, interaction, yt_info, false, msg);
return false;
}
function fromMessage(bot, command, interaction) {
//Setup data[1] = {info: yt_info, resource: resource}
const guildId = interaction.guildId;
let data = bot.audioData.get(guildId);
if (!data) { return interaction.reply("No music is currently playing!"); }
const player = data[0];
const message = interaction.channel.messages.cache.get(data[2]);
// console.log(message);
var em;
if (message.embeds) { em = message.embeds[0]; }
var rows;
if (command == 'stop') {
em = message.embeds[0];
rows = [];
em.description = new String;
em.description = 'IS NOW STOPPED';
player.stop();
const connection = getVoiceConnection(guildId);
if (connection) { connection.destroy(); }
bot.audioData.delete(guildId);
interaction.reply("Audio stopped!");
} else if (command == 'skip') {
if (playNext(null, bot, message)) {
rows = [];
em = message.embeds[0];
em.description = new String;
em.description = 'IS NOW STOPPED';
interaction.reply("Audio stopped!");
}
} else if (command == 'pause' || command == 'resume') {
interaction.deferReply();
pause_start_stop(null, bot, message, command);
interaction.deleteReply();
}
message.edit({embeds: [em], components: rows});
}
function showQueue(bot, isUpdate, interaction = null, page = 0) {
const guild = interaction.guildId;
const data = bot.audioData.get(guild);
if (!data) { return interaction.reply("The audio queue is empty!"); }
const rawQueue = data[1];
if (!rawQueue || rawQueue.length <= 0) { return interaction.reply("The audio queue is empty!"); }
const songList = [];
var tenSongs = '';
let i = 0;
rawQueue.forEach(function (rawSong) {
const songDetails = rawSong.yt_info.video_details;
tenSongs += `${i + 1}. ${songDetails.title}\n`;
i++;
//Split the songs into pages of 10
if (i % 10 == 0) { songList.push(tenSongs); tenSongs = ''; }
});
//If there's still some left over songs, add that
if (i % 10 != 0) {
songList.push(tenSongs);
}
if (page >= songList.length) { page = songList.length - 1 }
if (page < 0) { page = 0; } //LEAVE AS TWO IF's AS THE LENGTH MIGHT BE 0
if (songList.length == 0) { songList.push(tenSongs); }
//Create the embed
const author = {
name: "Selmer Bot",
url: "",
iconURL: bot.user.displayAvatarURL()
}
const newEmbed = new MessageEmbed()
.setTitle("SONG QUEUE")
.setAuthor(author)
.setDescription(songList[page])
.setFooter({ text: `Page ${page + 1}` })
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId(`audioQueue|${page - 1}`)
.setLabel('⬅️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId(`audioQueue|${page + 1}`)
.setLabel('➡️')
.setStyle('SECONDARY'),
)
if (isUpdate) {
interaction.update({embeds: [newEmbed], components: [row]});
} else {
interaction.reply({ embeds: [newEmbed], components: [row] }).catch((err) => {
console.log(err);
interaction.channel.send({ embeds: [newEmbed], components: [row] });
});
}
}
function removeFromQueue(bot, interaction, posStr) {
const guildId = interaction.guildId;
let data = bot.audioData.get(guildId);
if (!data) { return interaction.reply("The audio queue is empty!"); }
const rawQueue = data[1];
if (!rawQueue || rawQueue.length <= 0) { return interaction.reply("The audio queue is empty!"); }
else if (isNaN(posStr) || Number(posStr) > rawQueue.length) { return interaction.reply("Please specify a number within queue bounds!"); }
const pos = Number(posStr) - 1;
const details = rawQueue[pos].yt_info.video_details;
delete data[1][pos];
data[1] = data[1].filter(n => n);
bot.audioData.set(guildId, data);
const newEmbed = new MessageEmbed()
.setColor('#0F00F0')
.setTitle(`${details.title}`)
.setAuthor({ name: "Selmer Bot", url: "", iconURL: bot.user.displayAvatarURL() })
.setDescription( `has been removed from position ${pos + 1} in queue!`)
.setThumbnail(details.thumbnails[0].url);
interaction.reply({ embeds: [newEmbed] }).catch((err) => {
interaction.channel.send({ embeds: [newEmbed] });
console.log(err);
})
}
function shuffleQueue(bot, interaction) {
const guildId = interaction.guildId;
let data = bot.audioData.get(guildId);
if (!data) { return interaction.reply("The audio queue is empty!"); }
let rawQueue = data[1];
if (!rawQueue || rawQueue.length <= 0) { return interaction.reply("The audio queue is empty!"); }
//Shuffle the queue
rawQueue = rawQueue.sort(() => Math.random()-0.5);
data[1] = rawQueue;
bot.audioData.set(guildId, data);
interaction.reply("The queue has been shuffled!\nThe new queue is:").catch((err) => {
console.log(err);
interaction.channel.send("The queue has been shuffled!\nThe new queue is:");
});
showQueue(bot, false, interaction);
}
//[ { name: 'play', type: 'SUB_COMMAND', options: [ [Object] ] } ]
module.exports = {
name: "audio",
description: 'Play a song from YouTube, add free!',
async execute(interaction, Discord, Client, bot) {
const commandList = ['stop', 'skip', 'pause', 'resume'];
const command = interaction.options.data[0];
if (!command) {
return interaction.reply("Please specify a song or playlist!").chatch(err => {
console.log(err);
interaction.channel.send("Uh oh, there's been an error!");
});
}
// if (args.length < 1) {
// message.reply("Please use the following format _!audio [song name or URL]_ **or** _!audio queue_");
// return;
// } else
if (command.name == 'queue') {
return showQueue(bot, false, interaction);
} else if (commandList.indexOf(command.name) != -1) {
return fromMessage(bot, command.name, interaction);
} else if (command.name == 'remove') {
if (args.length < 2) { return interaction.reply("Please specify a position in queue!"); }
return removeFromQueue(bot, interaction, args[1].value);
} else if (command.name == 'shuffle') {
return shuffleQueue(bot, interaction);
}
/*
Re-introduce once the issue with ydtl-core is resolved (see
https://github.com/porridgewithraisins/jam-bot#known-bugs)
const stream = await ytdl(url, { filter: 'audioonly' });
*/
const channelId = interaction.guild.members.cache.get(interaction.user.id).voice.channelId;
if (!channelId) {
interaction.reply("Please join a voice channel before you try this!");
return;
}
const subCommand = command.options[0];
if (!subCommand) { return; }
interaction.deferReply();
if (subCommand.name == 'playlist') {
var isPremium;
await verPremium(bot, interaction.user.id).then(() => { isPremium = true; }).catch(() => { isPremium = false; });
const urls_promise = getPlaylistUrls(bot, subCommand.value, isPremium);
urls_promise.then(async (urls) => {
for (let i = 0; i < urls.length; i++) {
try {
const url = urls[i].video_url;
await playMusic(bot, interaction, channelId, url, true);
const msg = (i > 0) ? `Added ${i+1}/${urls.length} songs to queue` : `Added ${i+1}/${urls.length} song to queue`;
interaction.editReply(msg).catch((err) => { interaction.channel.send(msg); });
} catch(err) {
console.log(err);
}
}
}).catch(err => {
const msg = (err == "Request failed with status code 400") ? "Invalid playlist URL" : "uh oh, there's been an error";
console.log(err);
interaction.reply(msg).catch((err) => {
interaction.channel.send(msg);
});
});
} else {
const url = subCommand.value;
playMusic(bot, interaction, channelId, url);
interaction.deleteReply();
}
}, pause_start_stop, playNext, showQueue,
options: [
{name: 'play', description: 'play a song', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, options: [
{name: 'video', description: 'The song URL/search term(s)', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'playlist', description: 'The playlist URL', type: Constants.ApplicationCommandOptionTypes.STRING, required: false}
]},
{name: 'pause', description: 'Pause the currently playing song', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND},
{name: 'queue', description: 'Show the song queue', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND},
{name: 'remove', description: 'Remove a song from the queue', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND, options: [
{name: 'position', description: 'The song\'s position in queue', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: true}
]},
{name: 'resume', description: 'Resume playing the current song', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND},
{name: 'shuffle', description: 'Shuffle the song queue', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND},
{name: 'skip', description: 'skip the current song', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND},
{name: 'stop', description: 'stop the music and clear the queue', type: Constants.ApplicationCommandOptionTypes.SUB_COMMAND},
//Actions left: remove, shuffle,
]
}
+109 -83
View File
@@ -1,6 +1,6 @@
const { MongoClient, ServerApiVersion } = require('mongodb');
// const { update } = require('apt');
const { Collection, Client, Formatters, Intents } = require('discord.js');
const { Collection, Client, Formatters, Intents, Interaction } = require('discord.js');
const { CLIENT_ODBC } = require('mysql/lib/protocol/constants/client');
const { time } = require('@discordjs/builders');
@@ -31,14 +31,14 @@ function isNum(arg) {
};
function CreateNewCollection(message, client, server, id, opponent = null, game = null) {
function CreateNewCollection(interaction, client, server, id, opponent = null, game = null) {
const db = client.db(String(server));
const dbo = db.collection(id);
db.listCollections({name: id})
.next(function(err, collinfo) {
if (!collinfo) {
message.reply("You didn't have a place in my databases, so I created one for you!\nPlease try your command again!")
interaction.reply("You didn't have a place in my databases, so I created one for you!\nPlease try your command again!")
let hp_mp = {maxhp: BASE.HP, hp: BASE.HP, maxmp: BASE.MP, mp: BASE.MP}
dbo.insertOne({balance: 10, rank: 1, lastdayworked: 0, xp: 0, hpmp: hp_mp, game: game, gamesettings: {battle: {class: 'none', ultimate: true}}, opponent: opponent, state: STATE.IDLE, equipped: { weapons: {main: null, secondary: null}, items: {}}});
}
@@ -46,7 +46,7 @@ function CreateNewCollection(message, client, server, id, opponent = null, game
}
function addxp(message, dbo, amt, xp_list) {
function addxp(interaction, dbo, amt, xp_list) {
if (!isNum(amt)) { return console.log("This isn't a number...."); }
dbo.find({"balance": {$exists: true}}).toArray(function(err, doc) {
@@ -76,10 +76,12 @@ function addxp(message, dbo, amt, xp_list) {
let newmp = temp.mp + 5;
dbo.updateOne({balance: temp.balance, rank: temp.rank, lastdayworked: temp.lastdayworked}, { $set: { rank: rank, hpmp: {maxhp: newhp, maxmp: newmp} }});
message.channel.send('Congradulations <@' + message.author.id + '> for reaching rank ' + String(rank) + '!');
interaction.channel.send('Congradulations <@' + interaction.user.id + '> for reaching rank ' + String(rank) + '!');
}
} else {
message.reply("You've already reached max level!");
interaction.reply("You've already reached max level!").catch((err) => {
interaction.channel.send("You've already reached max level!");
});
}
dbo.updateOne({balance: temp.balance}, { $set: { xp: txp}});
@@ -87,25 +89,28 @@ function addxp(message, dbo, amt, xp_list) {
}
function getBalance(dbo, message) {
function getBalance(dbo, interaction) {
dbo.find({"balance": {$exists: true}}).toArray(function(err, doc) {
let bal = 0;
if (doc[0] && doc[0].balance) {
bal = doc[0].balance;
}
return message.reply(`<@${message.author.id}>, your current balance is ${currencySymbol}${bal}`);
return interaction.reply(`<@${interaction.user.id}>, your current balance is ${currencySymbol}${bal}`)
.catch((err) => {
interaction.channel.send(`<@${interaction.user.id}>, your current balance is ${currencySymbol}${bal}`);
});
});
}
function rank(dbo, message, xp_list) {
function rank(dbo, interaction, xp_list) {
dbo.find({"balance": {$exists: true}}).toArray(function(err, doc) {
if (!String(doc)) { return console.log("ERROR!\nThis account does not exist!"); }
let next = doc[0].rank + 1;
let needed = xp_list.get(next);
message.channel.send('<@' + message.author.id + '> you are currently at rank ' + String(next-1) + ' and have ' + String(doc[0].xp) + 'xp. You need ' + String(needed - doc[0].xp) + ' more xp to get to rank ' + String(next));
interaction.channel.send(`<@${interaction.user.id}'> you are currently at rank ${next-1} and have ${doc[0].xp}xp. You need ${needed - doc[0].xp} more xp to get to rank ${next}`);
});
}
@@ -115,22 +120,27 @@ function convertCurrency(id, amt, dbo) {
}
function checkAndUpdateBal(dbo, item, message, args) {
function checkAndUpdateBal(dbo, item, interaction, amt) {
return new Promise(function(resolve, reject) {
dbo.find({"balance": {$exists: true}}).toArray(b = function(err, doc) {
if (!String(doc)) {
message.reply("Your account doesn't exist, please contact the mods for support");
interaction.reply("Your account doesn't exist, please contact the mods for support").catch(() => {
interaction.channel.send("Your account doesn't exist, please contact the mods for support");
});
return false;
}
const icost = args[0] * item.cost;
const icost = amt * item.cost;
if (doc[0].balance < icost) {
message.reply("Insufficient funds!");
interaction.reply("Insufficient funds!").catch(() => { interaction.channel.send("Insufficient funds!"); });
resolve(false);
} else {
let temp = doc[0];
dbo.updateOne({balance: temp.balance, rank: temp.rank, lastdayworked: temp.lastdayworked}, { $set: { balance: doc[0].balance -= icost }});
message.reply(`You have bought ${item.name} for ${currencySymbol}${icost}!`);
interaction.reply(`You have bought ${item.name} for ${currencySymbol}${icost}!`).catch(() => {
interaction.channel.send(`You have bought ${item.name} for ${currencySymbol}${icost}!`);
});
resolve(true);
}
});
@@ -138,46 +148,51 @@ function checkAndUpdateBal(dbo, item, message, args) {
}
function buy(id, message, args, dbo, shop, xp_list) {
if (args.length < 2) { return; }
if (!isNum(args[0])) { return message.reply("Please enter a number for query 2"); }
function buy(id, interaction, dbo, shop, xp_list) {
const args = interaction.options.data;
let query = args[1];
//REAPPLY THIS TO OTHER FUNCTIONS
let query = args.filter((arg) => { return (arg.name == 'item'); })[0].value;
let amt = args.filter((arg) => { return (arg.name == 'amount'); })[0].value;
let item = shop.filter(function (item) { return item.name.toLowerCase() == query.toLowerCase(); })[0];
if (!String(item)) { return message.reply("This item does not exist!"); }
if (!String(item)) { return interaction.reply("This item does not exist!").catch(() => { interaction.channel.send("This item does not exist!"); }); }
// let success = Boolean(checkAndUpdateBal(dbo, item, message, args));
checkAndUpdateBal(dbo, item, message, args).then((success) => {
if (!success) { return } //The message is handled in the CheckAndUpdateBal() function
checkAndUpdateBal(dbo, item, interaction, amt).then((success) => {
//The message is handled in the CheckAndUpdateBal() function
if (!success) { return }
var newObj = { name: item.name, cost: item.cost, icon: item.icon, sect: item.sect};
addxp(message, dbo, Math.ceil(item.cost * 1.2), xp_list);
addxp(interaction, dbo, Math.ceil(item.cost * 1.2), xp_list);
dbo.find(newObj, {$exists: true}).toArray(function(err, doc) {
if(String(doc)) {
let newnum = doc[0].num + Number(args[0]);
let newnum = doc[0].num + amt;
dbo.updateOne({ name: item.name }, {$set: {num: newnum}});
} else {
item.num = amt;
// dbo.insertOne({ name: item.name, cost: item.cost, icon: item.icon, sect: item.sect, num: Number(args[0])}); //Causes "cyclic dependancy"
dbo.insertOne(item);
dbo.updateOne(item, { $set: {num: Number(args[0]) }});
dbo.updateOne(item, { $set: {num: amt }});
}
});
})
};
function sell(id, message, args, dbo, shop, xp_list) {
if (args.length < 2) { return; }
if (!isNum(args[0])) { return message.reply("Please enter a number for query 1"); }
let query = args[1];
var newObj = { name: query };
//FIXME
function sell(id, interaction, dbo, shop, xp_list) {
const args = interaction.options.data;
const query = args.filter((arg) => { return (arg.name == 'item'); })[0].value;
var num = args.filter((arg) => { return (arg.name == 'amount'); })[0].value;
let item = shop.filter(function (titem) { return titem.name.toLowerCase() == query.toLowerCase(); });
if (!String(item)) { return message.reply("This item does not exist!"); }
if (!String(item)) {
return interaction.reply("This item does not exist!").catch((err) => {
interaction.channel.send("This item does not exist!");
});
}
item[0] = {name: item[0].name, cost: item[0].cost, icon: item[0].icon, sect: item[0].sect};
@@ -187,7 +202,6 @@ function sell(id, message, args, dbo, shop, xp_list) {
if(String(doc)) {
//Make sure you don't sell more than you have
let num = Number(args[0]);
if (num < doc[0].num) {
let newNum = doc[0].num - num;
dbo.updateOne({ name: item[0].name }, {$set: {num: newNum}});
@@ -204,23 +218,34 @@ function sell(id, message, args, dbo, shop, xp_list) {
dbo.updateOne({"balance": {$exists: true}}, { $set: { balance: currentBal + amountSoldFor }});
});
addxp(message, dbo, Math.ceil(functional_item.cost * 1.2), xp_list);
addxp(interaction, dbo, Math.ceil(functional_item.cost * 1.2), xp_list);
message.reply(`You've sold ${num} ${String(functional_item.name)} for ${currencySymbol}${amountSoldFor}`);
interaction.reply(`You've sold ${num} ${String(functional_item.name)} for ${currencySymbol}${amountSoldFor}`)
.catch((err) => {
interaction.channel.send(`You've sold ${num} ${String(functional_item.name)} for ${currencySymbol}${amountSoldFor}`);
});
} else {
message.reply("You don't own this item!");
interaction.reply("You don't own this item!").catch((err) => {
interaction.channel.send(`You've sold ${num} ${String(functional_item.name)} for ${currencySymbol}${amountSoldFor}`);
});
}
});
}
function work(dbo, message, xp_list) {
function work(dbo, interaction, xp_list) {
let fulldate = new Date();
let date = fulldate.getDate();
dbo.find({"lastdayworked": {$exists: true}}).toArray(function(err, doc) {
if (!String(doc)) { return message.reply("Your account doesn't exist, please contact the mods for support"); }
if (!String(doc)) {
return interaction.reply("Your account doesn't exist, please contact the mods for support").catch((err) => {
interaction.channel.send("Your account doesn't exist, please contact the mods for support");
});
}
if (doc[0].lastdayworked == date) {//date
message.reply("You've already worked today, try again tomorrow!");
interaction.reply("You've already worked today, try again tomorrow!").catch((err) => {
interaction.channel.send("You've already worked today, try again tomorrow!");
});
} else {
//Amount to be paid
let amt = 0;
@@ -229,14 +254,16 @@ function work(dbo, message, xp_list) {
//Update the amount to the new TOTAL balance
dbo.updateOne({"balance": {$exists: true}}, { $set: { balance: doc[0].balance + amt, lastdayworked: date }});
addxp(message, dbo, xp_earned, xp_list);
message.channel.send(`<@${message.author.id}> worked and earned ${currencySymbol}${amt} and ${xp_earned} xp!`);
addxp(interaction, dbo, xp_earned, xp_list);
interaction.reply(`<@${interaction.user.id}> worked and earned ${currencySymbol}${amt} and ${xp_earned} xp!`).catch((err) => {
interaction.channel.send(`<@${interaction.user.id}> worked and earned ${currencySymbol}${amt} and ${xp_earned} xp!`)
});
}
});
}
function printInventory(dbo, message) {
function printInventory(dbo, interaction) {
let tempstring = "";
dbo.find().toArray(function(err, docs){
docs.forEach(val => {
@@ -246,44 +273,50 @@ function printInventory(dbo, message) {
});
if (tempstring == "") { tempstring += "You have nothing in your inventory!"; }
message.reply(tempstring);
interaction.reply(tempstring).catch((err) => {
interaction.channel.send(tempstring);
});
});
}
function getShop(message, args, items, bot) {
if (args.length == 0) {
let temp = Formatters.codeBlock(items.map(i => `${i.sect}`).join(' '));
temp = [...new Set(temp.split(' '))];
function getShop(interaction, items, bot) {
const args = interaction.options.data;
const type = args.filter((arg) => { return (arg.name == 'type'); })[0].value.toLowerCase();
return message.reply(`Please use the format ${bot.prefix}shop [type] [page number]\nTypes are: ${temp}`);
}
// if (args.length == 0) {
// let temp = Formatters.codeBlock(items.map(i => `${i.sect}`).join(' '));
// temp = [...new Set(temp.split(' '))];
// return message.reply(`Please use the format ${bot.prefix}shop [type] [page number]\nTypes are: ${temp}`);
// }
let ind = 1;
let noinp = false;
if (args.length > 1) {
if (args[1] < (items.length / 9)) {
ind = Number(args[1]);
const amt = args.filter((arg) => { return (arg.name == 'page'); })[0].value;
if (amt.value < (items.length / 9)) {
ind = Number(amt);
} else {
return message.reply("That number is too large");
return interaction.reply("That number is too large").catch(() => { interaction.channel.send("That number is too large"); });
}
} else {
noinp = true;
}
const items2 = items.filter(function(f) { return (f.sect.toLowerCase() == args[0].toLowerCase()) }).slice((ind - 1)*10, (ind - 1)*10+10);
const items2 = items.filter(function(f) { return (f.sect.toLowerCase() == type) }).slice((ind - 1)*10, (ind - 1)*10+10);
newText = Formatters.codeBlock(items2.map(i => `${i.icon} (${i.name}): $${i.cost}`).join('\n')); //${currencySymbol} doesn't owrk for some reason
if (noinp) {
newText += `(Use ${bot.prefix}shop [type] [page number] to access other pages)`;
}
return message.reply(newText);
return interaction.reply(newText).catch(() => { interaction.channel.send(newtext); });
}
function econHelp() {
let l = ["buy", 'shop', 'work', 'rank', 'inventory', 'balance', 'sell']
let l = ["buy", 'shop', 'work', 'rank', 'inventory', 'balance', 'sell'];
return l.join(", ");
}
@@ -293,10 +326,11 @@ function econHelp() {
module.exports = {
name: 'econ',
description: 'ECON',
async execute(bot, message, args, command, Discord, mongouri, items, xp_list) {
async execute(bot, interaction, Discord, mongouri, items, xp_list) {
//Set Discord vars
const id = message.author.id;
const server = message.guild.id;
const id = interaction.user.id;
const server = interaction.guildId;
const command = interaction.commandName;
// const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
// if (client.writeConcern || client.writeConcern) {
@@ -308,14 +342,14 @@ module.exports = {
bot.mongoconnection.then(async (client) => {
//Initialize if necessary
CreateNewCollection(message, client, server, id);
CreateNewCollection(interaction, client, server, id);
const db = client.db(String(server));
const dbo = db.collection(id);
currencySymbol = bot.currencysymbolmmain;
//test area
/*/test area
if (command == 'xp' || command == 'adbal') {
//Selmer Dev only command
if (message.member.roles.cache.has('944048889038774302')) {
@@ -323,7 +357,7 @@ module.exports = {
return addxp(message, dbo, Number(args[0]), xp_list);
}
}
}
}*/
//Command Area
if(command == 'init') {
@@ -331,37 +365,29 @@ module.exports = {
// init.execute(bot, message, args, command, dbo, Discord, connect);
return;
} else if (command == 'buy') {
buy(id, message, args, dbo, items, xp_list);
buy(id, interaction, dbo, items, xp_list);
} else if (command == 'shop') {
getShop(message, args, items, bot);
getShop(interaction, items, bot);
} else if (command == 'work') {
work(dbo, message, xp_list);
work(dbo, interaction, xp_list);
} else if (command == 'rank') {
rank(dbo, message, xp_list);
rank(dbo, interaction, xp_list);
} else if (command == 'inventory') {
printInventory(dbo, message);
printInventory(dbo, interaction);
} else if (command == 'balance') {
getBalance(dbo, message);
getBalance(dbo, interaction);
} else if (command == 'sell') {
sell(id, message, args, dbo, items, xp_list);
sell(id, interaction, dbo, items, xp_list);
} else {
message.channel.send("'" + message.content + "' is not a command!");
interaction.reply(`${command} is not a command`).catch((err) => {
interaction.channel.send(`${command} is not a command`);
});
}
});
},
//Battle Updating stuff
addxp, checkAndUpdateBal, CreateNewCollection, econHelp, addxp, BASE, STATE
}
/*
?????????????? What did I need this for?
else if (command == 'checkinv') {
const req = dbo.findOne({ id: message.guild.id });
if (!req) { return message.reply("Doc doesn't exist!"); }
}
*/
addxp, checkAndUpdateBal, CreateNewCollection, econHelp, addxp, BASE, STATE,
options: []
}
+31
View File
@@ -0,0 +1,31 @@
const { Constants } = require('discord.js');
module.exports = {
//Add the items on boot-up
"buy": {
description: 'Buy an item from the shop',
options: [
{name: 'item', description: 'the item you want to buy', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: []},
{name: 'amount', description: 'item amount', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: true, choices: []},
]},
'shop': {
description: 'Displays the shop',
options: [
{name: 'type', description: 'the type of item', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: [{name: 'Food', value: 'Food'}, {name: 'Weapons', value: 'Weapons'}, {name: 'HP', value: 'HP'}, {name: 'MP', value: 'MP'}]},
{name: 'page', description: 'the shop page you want to go to', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: false},
]
}, 'work': {
description: 'Work and earn money and xp',
options: []
},
'rank': { description: 'See your current rank' },
'inventory': { description: 'Check what\'s in your inventory' },
'balance': { description: 'Check your current balance' },
'sell': {
description: 'Sell an item from your inventory',
options: [
{name: 'item', description: 'the item you want to buy', type: Constants.ApplicationCommandOptionTypes.STRING, required: true},
{name: 'amount', description: 'the item you want to buy', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: true}
]
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ function devCheck(message, bot) {
const command = message.content.split(' ')[0].slice(1);
const args = message.content.split(' ')[1];
const member = bot.guilds.cache.get(bot.home_server).members.cache.get(message.author.id);
console.log(command);
//Check if they have the "Selmer Dev" role
if (member.roles.cache.has('944048889038774302')) {
switch (command) {
+21 -21
View File
@@ -217,31 +217,31 @@ module.exports ={
//#region Setup
const id = message.author.id;
const server = message.guild.id;
const id = message.author.id;
const server = message.guild.id;
// // @ts-ignore
// const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
// if (client.writeConcern || client.writeConcern) {
// client.close();
// return message.reply("Something went wrong with the database, please try again later and contact support if this problem persists!");
// }
var client;
await bot.mongoconnection.then((client1) => {
client = client1;
});
// // @ts-ignore
// const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
// if (client.writeConcern || client.writeConcern) {
// client.close();
// return message.reply("Something went wrong with the database, please try again later and contact support if this problem persists!");
// }
var client;
await bot.mongoconnection.then((client1) => {
client = client1;
});
const botdb = client.db('B|S' + bot.user.id);
const serverinbotdb = botdb.collection(server);
const botdb = client.db('B|S' + bot.user.id);
const serverinbotdb = botdb.collection(server);
//Initialize if necessary
ecoimport.CreateNewCollection(message, client, server, id);
command = args[0];
//Initialize if necessary
ecoimport.CreateNewCollection(message, client, server, id);
command = args[0];
//Check for a second person and create a second database entry if neccessary
if (message.mentions.users.first() != undefined) {
ecoimport.CreateNewCollection(message, client, server, message.mentions.users.first().id);
}
//Check for a second person and create a second database entry if neccessary
if (message.mentions.users.first() != undefined) {
ecoimport.CreateNewCollection(message, client, server, message.mentions.users.first().id);
}
//#endregion
const db = client.db(String(server));
+9 -6
View File
@@ -1,9 +1,10 @@
const { MongoClient, ServerApiVersion } = require('mongodb');
const { createSubscriptionManual } = require('./premium/stripe.js');
const { pause_start_stop, playNext, showQueue } = require('./misc/playAudio.js');
const { pause_start_stop, playNext, showQueue } = require('./audio/audioMain.js');
const { resolveComplaint } = require('./dev only/submitcomplaint.js');
const { RSSInteractionHandler } = require('../side projects/RSSHandlers/rssFeed.js');
const reminders = require('./premium/reminders.js');
const tuto = require('../commands/Selmer Specific/intro');
const tuto = require('./Selmer Specific/tuto');
const mswpr = require('./games/minesweeper.js');
// const { RSSInteractionHandler } = require('./premium/rssFeed.js');
const { Interaction } = require('discord.js')
@@ -72,7 +73,7 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE
playNext(interaction, bot);
} else if (interaction.customId.indexOf('audioQueue|') != -1) {
const page = Number(interaction.customId.split('|')[1]);
showQueue(bot, interaction.message, interaction, page);
showQueue(bot, true, interaction, page);
} else {
pause_start_stop(interaction, bot);
}
@@ -147,9 +148,11 @@ async function handle_interaction(interaction, mongouri, turnManager, bot, STATE
//Handle the interaction here
}
} /*else if (interaction.customId.indexOf('RSS') != -1) {
RSSInteractionHandler(bot, interaction);
}*/ //menu else ifs here
} else if (interaction.customId.indexOf('RSS') != -1) {
if (bot.inDebugMode) {
RSSInteractionHandler(bot, interaction);
}
} //menu else ifs here
}
//Forms
+7 -10
View File
@@ -1,4 +1,3 @@
const { MongoClient, ServerApiVersion } = require('mongodb');
const Discord = require('discord.js');
const SEVCODES = {
none: 0,
@@ -9,18 +8,16 @@ const SEVCODES = {
const col_list = {0: '0ed300', 1: 'f6ff00', 2: 'ffa100', 3: 'FF0000'}
/**
*
* @param {*} bot
* @param {*} message the message the mod sent (AKA a DISCORD MESSAGE OBJECT)
* @param {Discord.Client} bot
* @param {Discord.Interaction} interaction the message the mod sent (AKA a DISCORD MESSAGE OBJECT)
*/
function log(bot, message, command, mentioned, reason, severity) {
function log(bot, interaction, command, mentioned, reason, severity) {
bot.mongoconnection.then(client => {
// if (err) { return console.log(err); }
client.db(message.guild.id).collection('SETUP').findOne({_id: 'LOG'}).then((doc) => {
if (!doc) { return message.channel.send("Server logs not set up yet!"); }
const channel = message.guild.channels.cache.get(doc.logchannel);
client.db(interaction.guildId).collection('SETUP').findOne({_id: 'LOG'}).then((doc) => {
if (!doc) { return interaction.reply("Server logs not set up yet!"); }
const channel = interaction.guild.channels.cache.get(doc.logchannel);
if (!channel) { return console.log("There is no specified log channel!"); }
//Check severity threshold
@@ -35,7 +32,7 @@ function log(bot, message, command, mentioned, reason, severity) {
.setColor(col_list[severity])
.setTitle(`User ${mentioned.username}#${mentioned.discriminator} has been ${action}`)
//.setURL('https://discordjs.guide/popular-topics/embeds.html#embed-preview')
.setDescription(`Reason: ${reason}\n Responsible Mod: ${message.author.username}#${message.author.discriminator}`)
.setDescription(`Reason: ${reason}\n Responsible Mod: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user})`)
.setThumbnail(mentioned.displayAvatarURL())
.setTimestamp();
+3 -2
View File
@@ -1,4 +1,4 @@
const { Formatters, MessageEmbed } = require('discord.js');
const { Formatters, MessageEmbed, Constants } = require('discord.js');
const CoinGecko = require('coingecko-api');
const CoinGeckoClient = new CoinGecko();
@@ -72,5 +72,6 @@ module.exports = {
console.error(err);
return message.reply("Uh Oh! There's been an error!");
}
}
},
options: [{name: 'qeury', description: 'Name or List', type: Constants.ApplicationCommandOptionTypes.STRING, required: true}]
}
+4 -3
View File
@@ -1,7 +1,8 @@
module.exports = {
name: "test",
description: "HI SELMER",
execute(message, args, Discord, Client, bot) {
message.channel.send("HI SELMER!!!");
}
execute(interaction, Discord, Client, bot) {
interaction.reply("HI SELMER!!!");
},
options: []
}
+17 -10
View File
@@ -1,28 +1,34 @@
const { modHelp } = require('../admin/moderation.js');
const { Constants } = require('discord.js');
//CHANGE THIS TO FORMS?
module.exports ={
name: "help",
description: "Gets help for all of Selmer Bot's commands",
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
const groups = new Map([['SBspec', ['arrow', 'extracredit', 'profile', 'quotes', 'code']], ['adminCommands', [ 'setup', 'lock', 'unlock', 'serverlock' ]]]);
var spec = "";
if (interaction.options.data[0]) {
spec = interaction.options.data[0].value;
}
if (args[0] == 'econ') {
if (spec == 'econ') {
let temp = "***Selmer Bot Commands (Econ):***\n";
temp += bot.commands.get('econ').econHelp();
temp += `\n\n(remember to use _'${bot.prefix}'_ before the command!)`;
return message.channel.send(temp);
return interaction.reply({ content: temp, ephemeral: true });
}
else if (args[0] == 'game') {
else if (spec == 'game') {
let temp = "***Selmer Bot Commands (Games):***\n";
temp += bot.commands.get('game').allGames.join(", ");
temp += `\n\n(remember to use _'${bot.prefix}game'_ before the command!)`;
return message.channel.send(temp);
temp += `\n\n_Note: due to how complicated this feature is, it will not be migrated to slash commands for now_`;
return interaction.reply({ content: temp, ephemeral: true });
}
else if (args[0] == 'admin') {
else if (spec == 'admin') {
let temp = `__**Selmer Bot Admin Commands**__\n`
Array.from(groups.get('adminCommands')).forEach(commName => {
let comm = bot.commands.get(commName);
@@ -36,7 +42,7 @@ module.exports ={
temp += '\n_setup_ - ***SERVER OWNER ONLY*** - use _!setup help_\n';
temp += `\n\n(remember to use _'${bot.prefix}'_ before the command!)`;
return message.channel.send(temp);
return interaction.reply({ content: temp, ephemeral: true });
}
let temp = "***Selmer Bot Commands:***\n";
@@ -73,6 +79,7 @@ module.exports ={
temp += `\n_(remember to use '${bot.prefix}' before the command!)_`;
message.channel.send(temp);
}
interaction.reply({ content: temp, ephemeral: true });
},
options: [{name: 'command', description: 'econ, game, or admin', type: Constants.ApplicationCommandOptionTypes.STRING, required: false, choices: [ { name: 'econ', value: 'econ' }, { name: 'game', value: 'game' }, {name: 'admin', value: 'admin'} ]}]
}
+24 -18
View File
@@ -1,26 +1,32 @@
const { Constants } = require('discord.js');
module.exports ={
name: 'kareoke',
description: 'Sing your least-favorite song with your favorite person, me!',
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
const arg = interaction.options.data[0].value;
if (arg == "help") { return interaction.reply({content: "Please pick out a song at https://www.karaoke-lyrics.net/\nThe command should look like\n/kareoke [link_here]"}); }
const axios = require('axios');
const cheerio = require('cheerio')
const url = args[0];
if (args[0] == undefined) {
message.channel.send("Please pick out a song at https://www.karaoke-lyrics.net/\nThe command should look like\n/kareoke [link_here]");
} else {
axios(url)
.then(response => {
const html = response.data;
const $ = cheerio.load(html);
lyrics = $('.para_row').text();
breakbar = "---------------------------------------------";
message.channel.send(breakbar + "\n" + lyrics + "\n" + breakbar);
//console.log(lyrics);
})
.catch(console.error);
}
}
const url = interaction.options.data[0].value;
axios(url)
.then(response => {
const html = response.data;
const $ = cheerio.load(html);
lyrics = $('.para_row').text();
breakbar = "---------------------------------------------";
message.channel.send(breakbar + "\n" + lyrics + "\n" + breakbar);
//console.log(lyrics);
})
.catch((err) => {
console.log(err);
interaction.reply("Please provide a valid url from https://www.karaoke-lyrics.net/");
});
},
options: [{name: 'url', description: 'the url of the song or "help"', type: Constants.ApplicationCommandOptionTypes.STRING, required: true}]
}
//TEST: https://www.karaoketexty.cz/texty-pisni/zoegirl/plain-170199
+4 -4
View File
@@ -1,15 +1,15 @@
module.exports = {
name: "links",
description: "A helpful list of links to all of Selmer's wonderful websites",
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
const newEmbed = new Discord.MessageEmbed()
.setColor('#002eff')
.setTitle("Selmer's Links")
.addFields(
{name: 'HyperGrader', value: "https://rpi.logicamodernapproach.com/"},
{name: 'Personal Website', value: "http://www.logicamodernapproach.com/rpi/intlogs22.bringsjord/#sec-3"}
{name: 'Personal Website', value: "http://www.logicamodernapproach.com/"}
);
message.channel.send({ embeds: [newEmbed] });
}
interaction.reply({ embeds: [newEmbed] });
}, options: []
}
+6 -5
View File
@@ -5,7 +5,8 @@ const { randomHexColor } = require('../admin/colorgen.js');
module.exports = {
name: 'meme',
description: 'Selmer Bot will post a random meme from reddit',
async execute(message, args, Discord, Client, bot) {
async execute(interaction, Discord, Client, bot) {
interaction.deferReply();
memes.random().then(meme => {
const newEmbed = new Discord.MessageEmbed()
@@ -15,7 +16,7 @@ module.exports = {
.setDescription(`category: ${meme.category}`)
.setImage(meme.image);
message.channel.send({ embeds: [newEmbed] });
interaction.editReply({ embeds: [newEmbed] });
}).catch(async err => {
console.log(err);
//Try a different way
@@ -23,7 +24,7 @@ module.exports = {
const response = await fetch('https://some-random-api.ml/meme');
const data = await response.json().catch(err => {
console.log(err);
return message.reply("_Uh oh, something's gone wrong!_");
return interaction.reply("_Uh oh, something's gone wrong!_");
});
const newEmbed = new Discord.MessageEmbed()
@@ -33,7 +34,7 @@ module.exports = {
.setDescription(`category: ${data.category}`)
.setImage(data.image);
message.channel.send({ embeds: [newEmbed] });
interaction.editReply({ embeds: [newEmbed] });
});
}
}, options: []
}
+10 -8
View File
@@ -1,4 +1,5 @@
// https://ponly.com/200-pick-up-lines/
const { Constants } = require('discord.js');
const cheesy = [
'If I said you had a good body would you hold it against me?',
@@ -280,32 +281,33 @@ const anime = [
module.exports = {
name: 'pickupline',
description: 'Get a pickup line from our selection of 200 lines!',
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
const nameList = new Map([['cheesy', cheesy], ['funny', funny], ['smooth', smooth], ['best', best], ['anime', anime]]);
const type = interaction.options.data[0].value;
if (args[0] == 'sources') {
if (type == 'sources') {
message.reply("The normal lines are from https://ponly.com/200-pick-up-lines/\nThe anime lines are from https://thoughtcatalog.com/january-nelson/2021/06/anime-pick-up-lines/")
.then((msg) => { msg.suppressEmbeds(true); })
return;
}
if (args.length < 1 || (!nameList.get(args[0]) && args[0] != 'random')) { return message.reply("Please use the following format !pickupline <'cheesy', 'funny', 'smooth', 'best', 'anime', 'random', 'sources'>"); }
var key;
if (args[0] == 'random') {
if (type == 'random') {
let keyInd = Math.floor(Math.random() * nameList.size);
key = Array.from(nameList.keys())[keyInd];
} else {
key = args[0];
key = type;
}
const arr = nameList.get(key);
keyInd = Math.floor(Math.random() * arr.length);
try {
message.reply(arr[keyInd]);
interaction.reply(arr[keyInd]);
} catch {
message.channel.send(arr[keyInd]);
interaction.channel.send(arr[keyInd]);
}
}
},
options: [{name: 'type', description: 'Pick the genre of line or take a chance with random!', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: [{name: "cheesy", value: "cheesy"}, {name: "funny", value: "funny"}, {name: "smooth", value: "smooth"}, {name: "best", value: "best"}, {name: "anime", value: "anime"}, {name: "random", value: "random"}, {name: "sources", value: "sources"} ] }]
}
-459
View File
@@ -1,459 +0,0 @@
const pathToFfmpeg = require('ffmpeg-static');
// const { joinVoiceChannel, createAudioResource } = require('@discordjs/voice');
const { VoiceConnectionStatus, AudioPlayerStatus, createAudioPlayer, StreamType, joinVoiceChannel, createAudioResource, getVoiceConnection } = require('@discordjs/voice');
const { MessageActionRow, MessageButton, MessageEmbed, MessageSelectMenu, Message } = require('discord.js');
const play = require('play-dl');
// Note: Unsure of what this does , but may be related to the play-dl lib (my notes are inconsistent)
// play.authorization();
function playStopEmbed(bot, interaction, yt_info, stopped, message = null) {
if (stopped) {
var em = interaction.message.embeds[0];
rows = [];
em.description = new String;
em.description = 'IS NOW STOPPED';
interaction.update({embeds: [em], components: rows});
} else {
const author = {
name: "Selmer Bot",
url: "",
iconURL: bot.user.displayAvatarURL()
}
const newEmbed = new MessageEmbed()
.setColor('#0F00F0')
.setTitle(`${yt_info.video_details.title}`)
.setAuthor(author)
.setDescription('IS NOW PLAYING')
.setURL(yt_info.video_details.url)
.setThumbnail(yt_info.video_details.thumbnails[0].url);
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId('PAUSE')
.setLabel('⏸️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('STOP')
.setLabel('⏹️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('SKIP')
.setLabel('⏭️')
.setStyle('SECONDARY')
);
if (message) {
const m = message.reply({ embeds: [newEmbed], components: [row] });
m.then((msg) => {
const data = bot.audioData.get(message.guild.id);
data[2] = msg.id;
bot.audioData.set(message.guild.id, data);
})
} else {
interaction.update({embeds: [newEmbed], components: [row]});
}
}
}
function pause_start_stop(interaction, bot, message = null, command = null) {
try {
var player, em;
if (interaction) {
player = bot.audioData.get(interaction.guildId)[0];
command = interaction.customId.toLowerCase();
em = interaction.message.embeds[0];
} else {
player = bot.audioData.get(message.guild.id)[0];
em = message.embeds[0];
}
var rows = [new MessageActionRow()];
if (command == "pause") {
rows[0].addComponents(
new MessageButton()
.setCustomId('RESUME')
.setLabel('▶️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('STOP')
.setLabel('⏹️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('SKIP')
.setLabel('⏭️')
.setStyle('SECONDARY')
);
em.description = 'IS NOW PAUSED';
player.pause();
} else if (command == "resume") {
rows[0].addComponents(
new MessageButton()
.setCustomId('PAUSE')
.setLabel('⏸️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('STOP')
.setLabel('⏹️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId('SKIP')
.setLabel('⏭️')
.setStyle('SECONDARY')
);
em.description = 'IS NOW PLAYING';
player.unpause();
} else if (command == "stop") {
playStopEmbed(bot, interaction, null, true);
const connection = getVoiceConnection(interaction.guild.id);
player.stop();
//Remove everything from queue
bot.audioData.delete(interaction.guildId);
if (connection) { connection.destroy(); }
return;
}
if (interaction) { interaction.update({embeds: [em], components: rows}); }
else {
const data = bot.audioData.get(message.guild.id);
// var msg = message.channel.messages.cache.get(data[2]);
const newEmbed = message.embeds[0];
newEmbed.description = "Has been deferred";
message.edit({ embeds: [ newEmbed ], components: []});
const m = message.reply({embeds: [em], components: rows});
m.then((msg) => {
const data = bot.audioData.get(message.guild.id);
data[2] = msg.id;
bot.audioData.set(message.guild.id, data);
})
}
} catch (e) {
console.log(e);
rows = [];
em.description = new String('IS NOW STOPPED');
interaction.update({embeds: [em], components: rows});
}
}
function playNext(interaction, bot, message = null) {
// https://discordjs.guide/voice/audio-player.html#taking-action-within-the-error-handler
//Setup data[1] = {info: yt_info, resource: resource}
var guildId;
if (message != null) { guildId = message.guild.id; }
else { guildId = interaction.guildId; }
let data = bot.audioData.get(guildId);
const player = data[0];
//Check if the queue is empty
if (data[1].length <= 0) {
player.stop();
bot.audioData.delete(guildId);
if (message) { return true; }
else { return playStopEmbed(bot, interaction, null, true); }
}
const resource = data[1][0].resource;
const yt_info = data[1][0].yt_info;
player.stop();
//Play the thing
player.play(resource);
//remove the song from queue
delete data[1][0];
data[1] = data[1].filter(n => n);
bot.audioData.set(guildId, data);
//Add the embed
var msg = message;
if (!message) {
msg = interaction.message;
interaction.update({ embeds: [ new MessageEmbed(interaction.message.embeds[0]).setDescription("IS NOW STOPPED") ], components: []});
}
playStopEmbed(bot, interaction, yt_info, false, msg);
return false;
}
function fromMessage(bot, command, msg) {
//Setup data[1] = {info: yt_info, resource: resource}
const guildId = msg.guild.id;
let data = bot.audioData.get(guildId);
if (!data) { return msg.reply("No music is currently playing!"); }
const player = data[0];
const message = msg.channel.messages.cache.get(data[2]);
// console.log(message);
var em;
if (message.embeds) { em = message.embeds[0]; }
var rows;
if (command == 'stop') {
em = message.embeds[0];
rows = [];
em.description = new String;
em.description = 'IS NOW STOPPED';
player.stop();
const connection = getVoiceConnection(guildId);
if (connection) { connection.destroy(); }
bot.audioData.delete(guildId);
msg.reply("Audio stopped!");
} else if (command == 'skip') {
if (playNext(null, bot, message)) {
rows = [];
em = message.embeds[0];
em.description = new String;
em.description = 'IS NOW STOPPED';
msg.reply("Audio stopped!");
}
} else if (command == 'pause' || command == 'resume') {
pause_start_stop(null, bot, message, command);
}
message.edit({embeds: [em], components: rows});
}
function showQueue(bot, message, interaction = null, page = 0) {
const guild = message.guild.id;
const data = bot.audioData.get(guild);
if (!data) { return message.reply("The audio queue is empty!"); }
const rawQueue = data[1];
if (!rawQueue || rawQueue.length <= 0) { return message.reply("The audio queue is empty!"); }
const songList = [];
var fiveSongs = '';
let i = 0;
rawQueue.forEach(function (rawSong) {
const songDetails = rawSong.yt_info.video_details;
fiveSongs += `${i + 1}. ${songDetails.title}\n`;
i++;
//Split the songs into pages of 10
if (i % 10 == 0) { songList.push(fiveSongs); fiveSongs = ''; }
});
if (page >= songList.length) { page = songList.length - 1 }
if (page < 0) { page = 0; } //LEAVE AS TWO IF's AS THE LENGTH MIGHT BE 0
if (songList.length == 0) { songList.push(fiveSongs); }
//Create the embed
const author = {
name: "Selmer Bot",
url: "",
iconURL: bot.user.displayAvatarURL()
}
const newEmbed = new MessageEmbed()
.setTitle("SONG QUEUE")
.setAuthor(author)
.setDescription(songList[page])
.setFooter({ text: `Page ${page + 1}` })
const row = new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId(`audioQueue|${page - 1}`)
.setLabel('⬅️')
.setStyle('SECONDARY'),
new MessageButton()
.setCustomId(`audioQueue|${page + 1}`)
.setLabel('➡️')
.setStyle('SECONDARY'),
)
if (interaction) {
interaction.update({embeds: [newEmbed], components: [row]});
} else {
message.reply({ embeds: [newEmbed], components: [row] });
}
}
function removeFromQueue(bot, message, posStr) {
const guildId = message.guild.id;
let data = bot.audioData.get(guildId);
if (!data) { return message.reply("The audio queue is empty!"); }
const rawQueue = data[1];
if (!rawQueue || rawQueue.length <= 0) { return message.reply("The audio queue is empty!"); }
else if (isNaN(posStr) || Number(posStr) > rawQueue.length) { return message.reply("Please specify a number within queue bounds!"); }
const pos = Number(posStr) - 1;
const details = rawQueue[pos].yt_info.video_details;
delete data[1][pos];
data[1] = data[1].filter(n => n);
bot.audioData.set(guildId, data);
const newEmbed = new MessageEmbed()
.setColor('#0F00F0')
.setTitle(`${details.title}`)
.setAuthor({ name: "Selmer Bot", url: "", iconURL: bot.user.displayAvatarURL() })
.setDescription( `has been removed from position ${pos + 1} in queue!`)
.setThumbnail(details.thumbnails[0].url);
message.reply({ embeds: [newEmbed] });
}
function shuffleQueue(bot, message) {
const guildId = message.guild.id;
let data = bot.audioData.get(guildId);
if (!data) { return message.reply("The audio queue is empty!"); }
let rawQueue = data[1];
if (!rawQueue || rawQueue.length <= 0) { return message.reply("The audio queue is empty!"); }
//Shuffle the queue
rawQueue = rawQueue.sort(() => Math.random()-0.5);
data[1] = rawQueue;
bot.audioData.set(guildId, data);
message.reply("The queue has been shuffled!\nThe new queue is:");
showQueue(bot, message);
}
module.exports = {
name: "audio",
description: 'Play a song from YouTube, add free!',
async execute(message, args, Discord, Client, bot, interaction = null) {
const commandList = ['stop', 'skip', 'pause', 'resume'];
if (args.length < 1) {
message.reply("Please use the following format _!audio [song name or URL]_ **or** _!audio queue_");
return;
} else if (args[0] == 'queue') {
return showQueue(bot, message);
} else if (commandList.indexOf(args[0]) != -1) {
return fromMessage(bot, args[0], message);
} else if (args[0] == 'remove') {
if (args.length < 2) { return message.reply("Please specify a position in queue!"); }
return removeFromQueue(bot, message, args[1]);
} else if (args[0] == 'shuffle') {
return shuffleQueue(bot, message);
}
/*
Re-introduce once the issue with ydtl-core is resolved (see
https://github.com/porridgewithraisins/jam-bot#known-bugs)
const stream = await ytdl(url, { filter: 'audioonly' });
*/
if (!message.member.voice.channel) {
message.reply("Please join a voice channel before you try this!");
return;
}
const channel = bot.channels.cache.get(message.member.voice.channel.id);
// console.log(message.member.voice.channel.id);
const connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
});
connection.on(VoiceConnectionStatus.Ready, () => {
// console.log('Connected to the voice channel!');
});
let stream;
let yt_info;
if (args[0].startsWith("https://")) {
if (!args[0].startsWith("https://www.youtube.com/") &&
!args[0].startsWith("https://music.youtube.com/")) {
message.reply("This is not a valid YouTube URL");
return;
}
yt_info = await play.video_info(args[0]);
// let stream = await play.stream_from_info(yt_info)
stream = await play.stream(args[0]);
// console.log("Playing from a URL!");
} else {
yt_info = await play.search(args.join(' '), {
limit: 1
});
stream = await play.stream(yt_info[0].url);
yt_info = await play.video_info(yt_info[0].url);
}
let resource = createAudioResource(stream.stream, {
inputType: stream.type
})
// let audio = "em.mp3";
// let resource = createAudioResource(join(__dirname, audio));
const data = bot.audioData.get(channel.guild.id);
if (data && data[1]) {
//[player, [queue Array]]
data[1].push({yt_info: yt_info, resource: resource});
bot.audioData.set(message.guild.id, data);
message.reply(`_"${yt_info.video_details.title}" added to queue!_`);
} else {
const player = createAudioPlayer();
connection.subscribe(player);
bot.audioData.set(message.guild.id, [player, new Array(), null]);
player.play(resource);
player.on(AudioPlayerStatus.Playing, () => {
//Check maybe?
});
playStopEmbed(bot, interaction, yt_info, false, message);
}
}, pause_start_stop, playNext, showQueue
}
+33 -16
View File
@@ -1,13 +1,12 @@
const { MessageEmbed } = require('discord.js');
const { MessageEmbed, Constants } = require('discord.js');
//!poll <name> <option 1, option 2> [option 3...option 10]
module.exports = {
name: "poll",
description: "Create a cool poll embed (with time up to 1 hour!)",
async execute(message, args, Discord, Client, bot) {
if (args.length < 3) { return message.reply("Please provide a poll name, time (like 1:25 or 0 for not timed) and 1 - 10 options!"); }
if (args.length > 12) { return message.reply("Please specify less than 10 options!"); }
async execute(interaction, Discord, Client, bot) {
const args = interaction.options.data;
const timeList = [ '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟' ];
const author = {
@@ -15,32 +14,36 @@ module.exports = {
url: "",
iconURL: bot.user.displayAvatarURL()
}
const name = args.filter((arg) => { return (arg.name == 'question'); })[0].value;
var time = 0;
const time = interaction.options.data.filter((arg) => { return (arg.name == 'time'); })[0].value;
var temp;
var isTimed = !Number.isNaN(Number(args[1].split(":")[0]));
// var isTimed = !Number.isNaN(Number(args[1].split(":")[0]));
if (!isTimed) {
temp = `This poll was created by ${message.author} and has no time limit!\n`;
if (time != 0) {
temp = `This poll was created by ${interaction.user} and has no time limit!\n`;
} else {
time += (Number(args[1].split(':')[0]) * 60) + Number(args[1].split(':')[1]);
temp = `This poll was created by ${message.author} and ends <t:${Math.floor((new Date()).getTime()/1000) + time}:R>!\n`;
time += time * 60; // (Number(args[1].split(':')[0]) * 60) + Number(args[1].split(':')[1]);
temp = `This poll was created by ${interaction.user} and ends <t:${Math.floor((new Date()).getTime()/1000) + time}:R>!\n`;
}
//args[0] is the poll name
for(let i = 2; i < args.length; i ++) {
for(let i = 0; i < args.length; i ++) {
if (args[i].name.indexOf('option') == -1) { continue; }
// complist.push({ name: `${timeList[i - 1]}: ${args[i]}`, value: "" });
temp += `\n${timeList[i - 2]}: ${args[i]}\n`;
temp += `\n${timeList[i - 2]}: ${args[i].value}\n`;
}
const embd = new MessageEmbed()
.setTimestamp()
.setTitle(`${args[0]}`)
.setTitle(`${name}`)
.setDescription(temp)
.setAuthor(author)
message.channel.send({ embeds: [embd] }).then((msg) => {
const m = interaction.channel.send({ embeds: [embd] });
m.then((msg) => {
interaction.reply("Poll Posted!");
for(let i = 0; i < args.length - 2; i ++) {
msg.react(timeList[i]);
}
@@ -85,5 +88,19 @@ module.exports = {
msg.reply(temp);
});
});
}
},
options: [
{name: 'question', description: 'The poll question...', type: Constants.ApplicationCommandOptionTypes.STRING, required: true},
{name: 'time', description: 'the time the poll is open for in minutes (for no limit input 0)', type: Constants.ApplicationCommandOptionTypes.INTEGER, required: true},
{name: 'option1', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: true},
{name: 'option2', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option3', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option4', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option5', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option6', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option7', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option8', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option9', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
{name: 'option10', description: 'A poll option', type: Constants.ApplicationCommandOptionTypes.STRING, required: false},
]
}
+25 -20
View File
@@ -1,3 +1,5 @@
//NOTE: THIS FUNCTION REQUIRES REPLIES, AND I CAN'T FIGURE OUT HOW TO LINK THEM TO SLASH COMMANDS
module.exports = {
name: 'react',
description: "Reacts with a phrase or single emoji",
@@ -8,31 +10,34 @@ module.exports = {
if (message.reference) {
msg = await message.channel.messages.fetch(message.reference.messageId);
} else { msg = message; }
//Get rid of any custom emojis
console.log("IMPLEMENT THIS");
let emoji = [...new Set(args[0])];
if (emoji.length > 15 /*|| message.IndexOf(":") != -1*/) { return message.reply("Please enter less than 15 emojis"); }
let notused = new Array(15);
let counter = 0;
try {
let emoji = [...new Set(args[0])];
if (emoji.length > 15 /*|| message.IndexOf(":") != -1*/) { return message.reply("Please enter less than 15 emojis"); }
let notused = new Array(15);
let counter = 0;
for (let i = 0; i < emoji.length; i ++) {
try {
await msg.react(emoji[i]);
} catch(err) {
//The emoji wasn't a valid one
notused[counter] = emoji[i];
counter ++;
for (let i = 0; i < emoji.length; i ++) {
try {
await msg.react(emoji[i]);
} catch(err) {
//The emoji wasn't a valid one
notused[counter] = emoji[i];
counter ++;
}
}
}
if (notused.length > 0) {
notused = notused.filter(element => element !== undefined);
if (notused.length > 1) {
message.reply("These are not valid reaction emoji(s): " + notused.toString());
} else {
message.reply(notused.toString() + " is not a valid reaction emoji");
if (notused.length > 0) {
notused = notused.filter(element => element !== undefined);
if (notused.length > 1) {
message.reply("These are not valid reaction emoji(s): " + notused.toString());
} else {
message.reply(notused.toString() + " is not a valid reaction emoji");
}
}
} catch (err) {
console.log(err);
return message.reply("Uh oh, there's been an error");
}
}
}
+30 -24
View File
@@ -1,35 +1,41 @@
const hastebin = require("hastebin-gen");
const { addComplaintButton } = require('../dev only/submitcomplaint');
const { Constants } = require('discord.js');
module.exports ={
name: "scrape",
description: ".....",
async execute(message, args, Discord, Client, bot) {
description: "Scrapes a website, then puts the result into a hastebin",
async execute(interaction, Discord, Client, bot) {
const axios = require('axios');
const cheerio = require('cheerio');
const url = args[0];
axios(url)
.then(async response => {
const html = response.data;
const $ = cheerio.load(html);
//lyrics = $('.para_row').text();
// const cheerio = require('cheerio');
const url = interaction.options.data[0].value;
axios(url)
.then(async response => {
const html = response.data;
// const $ = cheerio.load(html);
//lyrics = $('.para_row').text();
const haste = await hastebin(html, { extension: "txt" });
message.channel.send(haste);
// console.log(lyrics);
})
.catch(function(err) {
if (err.message.indexOf('The "url" argument must be of type string') != -1) {
message.reply("The URL should be a string!");
} else if (err.code == 'ERR_BAD_REQUEST') {
message.reply("404 link not valid!")
} else {
message.reply("Oops! There's been an error, click the ✅ to report this!");
addComplaintButton(bot, message);
console.log(err);
}
const haste = await hastebin(html, { extension: "txt" });
interaction.reply(haste);
// console.log(lyrics);
})
.catch(function(err) {
if (err.message.indexOf('The "url" argument must be of type string') != -1) {
interaction.reply("The URL should be a string!");
} else if (err.code == 'ERR_BAD_REQUEST') {
interaction.reply("404 link not valid!")
} else {
const m = interaction.reply("Oops! There's been an error, click the ✅ to report this!");
m.then((msg) => {
addComplaintButton(bot, msg);
});
}
console.log(err);
}
});
},
options: [{name: 'url', description: 'The website URL', type: Constants.ApplicationCommandOptionTypes.STRING, required: true }]
}
//TEST: https://www.karaoketexty.cz/texty-pisni/zoegirl/plain-170199
+29 -28
View File
@@ -1,4 +1,4 @@
const { Modal, TextInputComponent, MessageActionRow, MessageButton, MessageEmbed, Interaction } = require('discord.js');
const { Constants, MessageEmbed, Interaction } = require('discord.js');
const dateFns = require('date-fns');
const { formatToTimeZone } = require('date-fns-timezone');
@@ -13,7 +13,7 @@ const alpaca = new Alpaca({
});
//This is the same as making the following request: https://data.alpaca.markets/v2/stocks/snapshots?symbols={stock_symbols_here}
async function getStockData(bot, message, args, stock) {
async function getStockData(bot, interaction, stock, type, after) {
try {
const snapshotPromise = alpaca.getSnapshot(stock);
@@ -22,7 +22,7 @@ async function getStockData(bot, message, args, stock) {
.setAuthor({ name: "Selmer Bot", url: "", iconURL: bot.user.displayAvatarURL() })
.setFooter({ text: 'Selmer Bot uses Alpaca for stock information'})
if (args[1] == 'trade') {
if (type) {
const lt = snapshot.LatestTrade;
embd.setTitle(`${stock} Latest Trade`)
.setTimestamp(lt.Timestamp)
@@ -33,9 +33,9 @@ async function getStockData(bot, message, args, stock) {
//This will always be IEX, as it is the only exchange the free version offers
{name: 'Exchange', value: `IEX (${lt.Exchange})`},
)
} else if (args[1] == 'quote') {
if (args[2] == 'after') {
return message.reply("Due to the markets not being open, there is no quote data available!");
} else if (type) {
if (after) {
return interaction.reply("Due to the markets not being open, there is no quote data available!");
}
const lq = snapshot.LatestQuote;
embd.setTitle(`${stock} Latest Quote`)
@@ -49,7 +49,7 @@ async function getStockData(bot, message, args, stock) {
//This will always be IEX, as it is the only exchange the free version offers
{name: 'Exchange', value: `IEX (${lq.Exchange})`},
)
} else if (args[1] == 'bars') {
} else if (type) {
const mb = snapshot.MinuteBar;
const db = snapshot.DailyBar;
const pdb = snapshot.PrevDailyBar;
@@ -61,23 +61,22 @@ async function getStockData(bot, message, args, stock) {
{name: 'Day Bar (Yesterday)', value: `Open Price: ${pdb.OpenPrice},\nClose Price: ${pdb.ClosePrice},\nHigh Price: ${pdb.HighPrice},\nLow Price: ${pdb.LowPrice},\nVolume: ${pdb.Volume},\nCount: ${pdb.TradeCount},\nVWAP: ${pdb.VWAP}`},
)
} else {
return message.reply("The command format is: _!stocks <stock_name, 'hours'> <trade, quote, bars> [after]_");
return interaction.reply("The command format is: _/stocks <stock_name, 'hours'> <trade, quote, bars> [after]_");
}
message.reply({embeds: [embd]});
interaction.reply({embeds: [embd]});
})
} catch(err) {
console.error(err);
message.reply("Uh Oh, there's been an error!");
interaction.reply("Uh Oh, there's been an error!");
}
}
function getData(bot, message, args) {
var stock;
if (args.length < 1) {
return message.reply("Please specify a stock (ex: AAPL, GOOG, etc)")
} else { stock = args[0];}
function getData(bot, interaction) {
const args = interaction.options.data;
const stock = args.filter((arg) => { return (arg.name == 'name')})[0].value;
const type = args.filter((arg) => { return (arg.name == 'type')})[0].value;
const after = (args.length > 2 && args.filter((arg) => { return (arg.name == 'after')})[0].value);
const format = `yyyy-MM-dd HH:mm:ss`;
const date = dateFns.format(new Date(), format);
@@ -90,17 +89,17 @@ function getData(bot, message, args) {
end: date
}).then((calendars) => {
let temp;
if (clock.is_open || args[2] == 'after') {
if (args[0] == 'hours') {
if (clock.is_open || after) {
if (stock == 'hours') {
temp = `The markets opened at ${calendars[0].open} and will close at ${calendars[0].close} on ${date}.`;
return message.reply(temp);
return interaction.reply(temp);
}
getStockData(bot, message, args, stock);
getStockData(bot, interaction, stock, type, after);
} else {
// `The market is currently ${clock.is_open ? 'open.' : 'closed.'}`
//May be innacurate?
temp = `_The markets closed at \`${calendars[0].close}\` and will open again at \`${calendars[0].open}\` on \`${dateFns.format((new Date()).setDate(new Date().getDate() + 1), 'yyyy-MM-dd')}\`.\nTo get the last snapshot before market closure, add the \`after\` keyword to the end of your command (trade and bars ONLY), ex: !stocks GOOG bars after_`;
return message.reply(temp);
temp = `_The markets closed at \`${calendars[0].close}\` and will open again at \`${calendars[0].open}\` on \`${dateFns.format((new Date()).setDate(new Date().getDate() + 1), 'yyyy-MM-dd')}\`.\nTo get the last snapshot before market closure, add the \`after\` keyword to the end of your command (trade and bars ONLY), ex: /stocks GOOG bars after_`;
return interaction.reply(temp);
}
});
})
@@ -111,10 +110,12 @@ function getData(bot, message, args) {
module.exports = {
name: 'stocks',
description: "Have Selmer Bot give you \"current\" stock prices",
async execute(message, args, Discord, Client, bot) {
if (args[0] == 'help' || args.length < 1) {
return message.reply("The command format is: _!stocks <stock_name, 'hours'> <trade, quote, bars> [after]_");
}
getData(bot, message, args);
}
async execute(interaction, Discord, Client, bot) {
getData(bot, interaction);
},
options: [
{name: 'name', description: 'the stock name or "hours" for market hours', type: Constants.ApplicationCommandOptionTypes.STRING, required: true},
{name: 'type', description: 'The type of data to present', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: [ { name: 'trade', value: 'trade' }, { name: 'quote', value: 'quote' }, {name: 'bars', value: 'bars'}]},
{name: 'after', description: 'If the markets are closed, get the last entry', type: Constants.ApplicationCommandOptionTypes.BOOLEAN, required: false},
]
}
+2 -2
View File
@@ -103,7 +103,7 @@ module.exports = {
name: 'chat',
description: 'chat',
convoManager,
execute(message, args, Discord, Client, bot) {
message.reply("Please DM Selmer bot to use this command!");
execute(interaction, args, Discord, Client, bot) {
interaction.reply("Please DM Selmer bot to use this command!");
}
}
+9 -8
View File
@@ -365,21 +365,21 @@ function turnPage(bot, interaction) {
module.exports = {
name: "reminders",
description: "Have Selmer Bot remind you - premium feature",
execute(message, args, Discord, Client, bot) {
execute(interaction, Discord, Client, bot) {
//Check if the user has premium
bot.mongoconnection.then(async (client) => {
const dbo = client.db('main').collection('authorized');
dbo.find({ discordID: message.author.id }).toArray((err, docs) => {
dbo.find({ discordID: interaction.user.id }).toArray((err, docs) => {
//Only available to Selmer Bot devs, testers and "authorized" users
if (docs[0] != undefined) {
//Execute the command
const row = new MessageActionRow()
if (message.channel.type == 'DM') {
if (interaction.channel.type == 'DM') {
row.addComponents(
new MessageButton()
.setCustomId(`newEvent|User|${message.author.id}`)
.setCustomId(`newEvent|User|${interaction.user.id}`)
.setLabel('New Personal Reminder')
.setStyle('SUCCESS'),
new MessageButton()
@@ -390,7 +390,7 @@ module.exports = {
} else {
row.addComponents(
new MessageButton()
.setCustomId(`newEvent|User|${message.author.id}`)
.setCustomId(`newEvent|User|${interaction.user.id}`)
.setLabel('New Personal Reminder')
.setStyle('SUCCESS'),
new MessageButton()
@@ -404,11 +404,12 @@ module.exports = {
);
}
return message.channel.send({ content: 'Please select an action\n_Notes: Adding offset to an event is only supported on the website and personal reminders can be viewed in DM\'s_', components: [row] });
return interaction.reply({ content: 'Please select an action\n_Notes: Adding offset to an event is only supported on the website and personal reminders can be viewed in DM\'s_', components: [row] });
} else {
message.reply("You have to be a premium subscriber to use this feature!\n_support coming soon_");
interaction.reply("You have to be a premium subscriber to use this feature!\n_support coming soon_");
}
});
});
}, modalHandle, turnPage
}, modalHandle, turnPage,
options: []
}
+26 -22
View File
@@ -3,9 +3,10 @@
https://selmer-bot-listener.ion606.repl.co
--------------------------------------------------
*/
//@ts-check
const { MongoClient, ServerApiVersion } = require('mongodb');
const { MessageActionRow, MessageSelectMenu } = require('discord.js');
const { MessageActionRow, MessageSelectMenu, Constants } = require('discord.js');
const { addComplaintButton } = require('../dev only/submitcomplaint');
@@ -79,10 +80,10 @@ async function createSubscriptionManual(bot, interaction, id, priceID) {
}
async function changeSubscriptionManual(bot, message) {
async function changeSubscriptionManual(bot, interaction) {
const stripe = bot.stripe;
const mongouri = bot.mongouri;
const id = message.author.id;
const id = interaction.user.id;
//Just in case
if (!id) { return console.log('....What? How?'); }
@@ -102,7 +103,7 @@ async function changeSubscriptionManual(bot, message) {
resolve(userID);
} else {
// client.close();
reject(`No user with the ID of <@${message.author.id}>`);
reject(`No user with the ID of <@${interaction.user.id}>`);
}
});
});
@@ -112,22 +113,22 @@ async function changeSubscriptionManual(bot, message) {
customer: userID,
return_url: "https://linktr.ee/selmerbot",
}).then((session) => {
message.reply(session.url);
interaction.reply(session.url);
})
}).catch((err) => {
if (String(typeof(err)) == 'string') {
message.reply(err);
interaction.reply(err);
} else {
console.log(err);
message.reply("A Stripe error occured! Please click the ✅ to report this ASAP!");
addComplaintButton(bot, interaction.message);
interaction.reply("A Stripe error occured! Please click the ✅ to report this ASAP!");
addComplaintButton(bot, interaction.message); //?????????
}
});
}
function createDropDown(bot, message) {
function createDropDown(bot, interaction) {
const stripe = bot.stripe;
const pl = [];
@@ -144,7 +145,7 @@ function createDropDown(bot, message) {
let n = Promise.all(pl);
let i = 0;
n.then((t) => {
n.then((t) => {
t.forEach(data => {
let price = data.unit_amount/100;
vl[i].description = `The $${price} tier`;
@@ -155,24 +156,25 @@ function createDropDown(bot, message) {
const row = new MessageActionRow()
.addComponents(
new MessageSelectMenu()
.setCustomId(`${message.author.id}|premium`)
.setCustomId(`${interaction.user.id}|premium`)
.setPlaceholder('Nothing selected')
.addOptions(vl)
);
message.channel.send({ content: `Please choose a tier`, components: [row] });
interaction.reply({ content: `Please choose a tier`, components: [row], ephemeral: true });
});
});
}
function handleInp(bot, message) {
if (message.content == '!premium' || message.content == '!premium help') {
message.reply('Use _!premium buy_ to get premium or use _!premium manage_ to change or cancel your subscription\n\n_Disclaimer: Selmer Bot uses Stripe to manage payments. Read more at *https://stripe.com/ *_');
} else if (message.content == '!premium buy') {
createDropDown(bot, message);
} else if (message.content == '!premium manage') {
changeSubscriptionManual(bot, message);
function handleInp(bot, interaction) {
const inp = interaction.options.data[0];
if (!inp || inp.value == 'help') {
interaction.reply({content: 'Use _!premium buy_ to get premium or use _!premium manage_ to change or cancel your subscription\n\n_Disclaimer: Selmer Bot uses Stripe to manage payments. Read more at *https://stripe.com/ *_', ephemeral: true});
} else if (inp.value == 'buy') {
createDropDown(bot, interaction);
} else if (inp.value == 'manage') {
changeSubscriptionManual(bot, interaction);
}
}
@@ -180,7 +182,9 @@ function handleInp(bot, message) {
module.exports = {
name: 'premium',
description: 'everything payment',
execute(message, args, Discord, Client, bot) {
message.reply("Please DM Selmer bot to use this command!");
}, handleInp, createSubscriptionManual
execute(interaction, Discord, Client, bot) {
handleInp(bot, interaction);
}, handleInp, createSubscriptionManual,
options: [{name: 'input', description: 'What do you want to do?', type: Constants.ApplicationCommandOptionTypes.STRING, required: true, choices: [{name: 'help', value: 'help'}, {name: 'buy', value: 'buy'}, {name: 'manage', value: 'manage'}]}],
isDM: true
}
+26
View File
@@ -0,0 +1,26 @@
/**
* Check if the user has a premium subscription
* @param {*} bot
* @param {String} userId
* @returns {Promise<Boolean>}
*/
function verPremium(bot, userId) {
return new Promise((resolve, reject) => {
const member = bot.guilds.cache.get(bot.home_server).members.cache.get(userId);
bot.mongoconnection.then(async (client) => {
const dbo = client.db('main').collection('authorized');
dbo.findOne({ discordID: userId }).then((doc) => {
//Only available to Selmer Bot devs, testers and "authorized" users
if (doc != undefined || member && (member.roles.cache.has('944048889038774302') || member.roles.cache.has('946610800418762792'))) {
resolve(true);
} else {
reject("You have to be a premium subscriber to use this feature!\n_support coming soon_");
}
});
});
});
}
module.exports = { verPremium }
+64 -30
View File
@@ -1,5 +1,5 @@
//#region imports
const { Client, Intents, MessageActionRow, MessageButton, MessageSelectMenu } = require('discord.js');
const { Client, Intents } = require('discord.js');
const Discord = require('discord.js');
const { MongoClient, ServerApiVersion } = require('mongodb');
const fs = require('fs');
@@ -13,6 +13,8 @@ const { handle_interaction } = require('./commands/interactionhandler.js');
const { handle_dm } = require('./commands/dm_handler');
const { devCheck } = require('./commands/dev only/devcheck.js');
const { moderation_handler } = require('./commands/admin/moderation.js');
const { registerCommands } = require('./registerCommands.js');
const { backupLists, loadBotBackups } = require('./commands/admin/backupBot.js');
const { exit } = require('process');
//#endregion
@@ -29,6 +31,7 @@ let debug_channel;
let MLAIKEY;
let StripeAPIKey;
let youtubeAPIKey;
if (process.env.token != undefined) {
//Use "setx NAME VALUE" in the local powershell terminal to set
@@ -37,6 +40,7 @@ if (process.env.token != undefined) {
debug_channel = process.env.debug_channel;
MLAIKEY = process.env.MLAIKEY;
StripeAPIKey = process.env.StripeAPIKey;
youtubeAPIKey = process.env.youtubeAPIKey;
} else {
token = require('./config.json').token;
home_server = require('./config.json').home_server;
@@ -44,8 +48,8 @@ if (process.env.token != undefined) {
MLAIKEY = require('./config.json').MLAIKEY;
StripeAPIKey = require('./config.json').StripeAPIKey;
youtubeAPIKey = require('./config.json').youtubeAPIKey;
// { token, home_server, debug_channel, MLAIKEY, StripeAPIKey } = require('./config.json'); // Doesn't work
IDM = true;
}
@@ -74,6 +78,7 @@ bot.inDebugMode = IDM;
bot.home_server = home_server;
bot.debug_channel = debug_channel;
bot.inviteLink = 'https://discord.com/oauth2/authorize?client_id=944046902415093760&scope=applications.commands+bot&permissions=549755289087';
bot.youtubeAPIKey = youtubeAPIKey;
const configuration = new Configuration({
apiKey: MLAIKEY,
@@ -85,6 +90,7 @@ bot.stripe = Stripe(StripeAPIKey);
//The first thing will be an audioPlayer(), the second a queue
bot.audioData = new Map();
bot.lockedChannels = new Map();
//#region MongoDB integration
//Development support
@@ -99,11 +105,26 @@ bot.mongouri = mongouri;
const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
bot.mongoconnection = client.connect();
const { connect } = require('mongoose');
//#endregion MongoDB Integration end
//#region PROCESS STUFF
loadBotBackups(bot, IDM);
process.on("SIGTERM", (signal) => {
console.log(`Process ${process.pid} received a SIGTERM signal`);
backupLists(bot, IDM);
// process.exit(0);
});
process.on("SIGINT", (signal) => {
console.log(`Process ${process.pid} has been interrupted`);
backupLists(bot, IDM);
// process.exit(0);
});
//#endregion
//#region set up bot commands
// const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js')); // Obsolete?
@@ -152,6 +173,8 @@ let xp_collection = new Map();
let items;
bot.on('ready', async () => {
registerCommands(bot);
//Make then copy the shop
bot.mongoconnection.then(client => {
const shop = client.db("main").collection("shop");
@@ -192,7 +215,27 @@ bot.on('ready', async () => {
//Button Section
bot.on('interactionCreate', async interaction => {
handle_interaction(interaction, mongouri, turnManager, bot, STATE, items, xp_collection);
const { commandName } = interaction;
bot.lockedChannels.set(interaction.guildId, ["NUMBERS HERE"]);
// console.log(bot.lockedChannels);
//Slash commands
if (interaction.isApplicationCommand()) {
const logable = ['kick', 'ban', 'unban', 'mute', 'unmute', 'timeout'];
const econList = ["buy", 'shop', 'work', 'rank', 'inventory', 'balance', 'sell'];
if (logable.includes(commandName)) {
moderation_handler(bot, interaction, commandName);
} else if (econList.includes(commandName)) {
bot.commands.get('econ').execute(bot, interaction, Discord, mongouri, items, xp_collection);
}
else if (bot.commands.has(commandName)) {
bot.commands.get(commandName).execute(interaction, Discord, Client, bot);
} else {
interaction.reply("Unknown command detected!");
}
} else {
handle_interaction(interaction, mongouri, turnManager, bot, STATE, items, xp_collection);
}
});
@@ -276,6 +319,7 @@ bot.on("guildDelete", guild => {
//Welcome new members
bot.on('guildMemberAdd', async (member) => {
if (member.guild.id == bot.home_server && !bot.inDebugMode) { return; }
//Check for impartial data
if(member.partial) await member.fetch();
@@ -286,6 +330,8 @@ bot.on('guildMemberAdd', async (member) => {
const dbo = client.db(member.guild.id).collection('SETUP');
dbo.find({_id: 'WELCOME'}).toArray(async (err, docs) => {
if (!docs) { return; }
var welcomechannel;
if (docs[0].welcomechannel == null) {
welcomechannel = guild.channels.cache.find(channel => channel.name.toLowerCase() === 'welcome');
@@ -320,35 +366,23 @@ bot.on('messageCreate', (message) => {
//Special case, testing server (still need the emojis and error logging)
if (!bot.inDebugMode && message.guild.id == bot.home_server) { return; }
//COMMAND AREA
//Check if the prefix exists
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(' ');
const command = args.shift().toLowerCase();
//Log logable commands then execute them
const logable = ['kick', 'ban', 'unban', 'mute', 'unmute', 'timeout'];
if (logable.includes(command)) {
moderation_handler(bot, message, args, command);
}
//Performes the command
//Admin section
else if (command == 'reactionrole') { bot.commands.get(command).execute(message, args, Discord, bot); }
else if(bot.commands.has(command) && command != 'ECON') {
//Database access is required, change the inputs
if (command == 'game' || command == 'accept' || command == 'setup') {
if (!message.content.startsWith(prefix) || message.author.bot) {
//Use for the leveling-by-interaction system
return;
} else {
//Game section (too complicated to move to Slash Commands)
//Note: Slash commands do not register as valid replies
const args = message.content.slice(prefix.length).split(' ');
const command = args.shift().toLowerCase();
if (command == 'game' || command == 'accept') {
bot.commands.get(command).execute(bot, message, args, command, Discord, mongouri, items, xp_collection);
} else {
bot.commands.get(command).execute(message, args, Discord, Client, bot);
} else if (command == 'rss' && bot.inDebugMode) {
const rss = require('./side projects/RSSHandlers/rssFeed.js');
rss.execute(message, args, Discord, client, bot);
}
}
//Econ and also the catch statement
else { bot.commands.get('econ').execute(bot, message, args, command, Discord, mongouri, items, xp_collection); }
})
});
//#endregion
+335 -1
View File
@@ -11,7 +11,7 @@
"dependencies": {
"@alpacahq/alpaca-trade-api": "^2.16.1",
"@discordjs/opus": "github:discordjs/opus",
"@discordjs/rest": "^1.0.1",
"@discordjs/rest": "^1.1.0",
"@discordjs/voice": "^0.8.0",
"@napi-rs/canvas": "^0.1.22",
"apt": "^0.0.2",
@@ -31,6 +31,7 @@
"feedparser": "^2.2.10",
"ffmpeg": "^0.0.4",
"ffmpeg-static": "^5.0.0",
"googleapis": "^107.0.0",
"hastebin-gen": "^2.0.5",
"html-entities": "^2.3.3",
"libsodium-wrappers": "^0.7.10",
@@ -811,6 +812,14 @@
"resolved": "https://registry.npmjs.org/arraybuffer-to-buffer/-/arraybuffer-to-buffer-0.0.7.tgz",
"integrity": "sha512-WAIA2Mq+KLJ7Ua40KD6zMshvSsJbnXRuVG0/MNEIPhIMEWRkcmLMcQvx0OkAeMIZi2jHJOXxK9ZqVJ+A+Z6knw=="
},
"node_modules/arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
"engines": {
"node": ">=8"
}
},
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -1003,6 +1012,11 @@
"ieee754": "^1.1.13"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -1540,6 +1554,14 @@
"safer-buffer": "^2.1.0"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -1697,6 +1719,11 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/fast-text-encoding": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
"integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
},
"node_modules/feedparser": {
"version": "2.2.10",
"resolved": "https://registry.npmjs.org/feedparser/-/feedparser-2.2.10.tgz",
@@ -1894,6 +1921,32 @@
"node": ">=10"
}
},
"node_modules/gaxios": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.0.1.tgz",
"integrity": "sha512-keK47BGKHyyOVQxgcUaSaFvr3ehZYAlvhvpHXy0YB2itzZef+GqZR8TBsfVRWghdwlKrYsn+8L8i3eblF7Oviw==",
"dependencies": {
"extend": "^3.0.2",
"https-proxy-agent": "^5.0.0",
"is-stream": "^2.0.0",
"node-fetch": "^2.6.7"
},
"engines": {
"node": ">=12"
}
},
"node_modules/gcp-metadata": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.0.0.tgz",
"integrity": "sha512-gfwuX3yA3nNsHSWUL4KG90UulNiq922Ukj3wLTrcnX33BB7PwB1o0ubR8KVvXu9nJH+P5w1j2SQSNNqto+H0DA==",
"dependencies": {
"gaxios": "^5.0.0",
"json-bigint": "^1.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@@ -1934,12 +1987,94 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/google-auth-library": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.5.1.tgz",
"integrity": "sha512-7jNMDRhenfw2HLfL9m0ZP/Jw5hzXygfSprzBdypG3rZ+q2gIUbVC/osrFB7y/Z5dkrUr1mnLoDNlerF+p6VXZA==",
"dependencies": {
"arrify": "^2.0.0",
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
"fast-text-encoding": "^1.0.0",
"gaxios": "^5.0.0",
"gcp-metadata": "^5.0.0",
"gtoken": "^6.1.0",
"jws": "^4.0.0",
"lru-cache": "^6.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/google-p12-pem": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz",
"integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==",
"dependencies": {
"node-forge": "^1.3.1"
},
"bin": {
"gp12-pem": "build/src/bin/gp12-pem.js"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/googleapis": {
"version": "107.0.0",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-107.0.0.tgz",
"integrity": "sha512-emMvsOEPvE9/DxrOVCMblQzKAhaar37c5JPAqYXoo+hxPpzFefkpN5ayIJFgatDpUWCSMvWtP3CcEWfFhFA7QA==",
"dependencies": {
"google-auth-library": "^8.0.2",
"googleapis-common": "^6.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/googleapis-common": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.3.tgz",
"integrity": "sha512-Xyb4FsQ6PQDu4tAE/M/ev4yzZhFe2Gc7+rKmuCX2ZGk1ajBKbafsGlVYpmzGqQOT93BRDe8DiTmQb6YSkbICrA==",
"dependencies": {
"extend": "^3.0.2",
"gaxios": "^5.0.1",
"google-auth-library": "^8.0.2",
"qs": "^6.7.0",
"url-template": "^2.0.8",
"uuid": "^9.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/googleapis-common/node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"optional": true
},
"node_modules/gtoken": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz",
"integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==",
"dependencies": {
"gaxios": "^5.0.1",
"google-p12-pem": "^4.0.0",
"jws": "^4.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -2266,6 +2401,17 @@
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
"optional": true
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -2299,6 +2445,14 @@
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"node_modules/json-bigint": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
"dependencies": {
"bignumber.js": "^9.0.0"
}
},
"node_modules/json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
@@ -2333,6 +2487,25 @@
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
"integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg=="
},
"node_modules/jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
"dependencies": {
"jwa": "^2.0.0",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kareem": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz",
@@ -2923,6 +3096,14 @@
"webidl-conversions": "^3.0.0"
}
},
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
"engines": {
"node": ">= 6.13.0"
}
},
"node_modules/node-gyp": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
@@ -6710,6 +6891,11 @@
"punycode": "^2.1.0"
}
},
"node_modules/url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
"integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
},
"node_modules/urljoin": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/urljoin/-/urljoin-0.1.5.tgz",
@@ -7516,6 +7702,11 @@
"resolved": "https://registry.npmjs.org/arraybuffer-to-buffer/-/arraybuffer-to-buffer-0.0.7.tgz",
"integrity": "sha512-WAIA2Mq+KLJ7Ua40KD6zMshvSsJbnXRuVG0/MNEIPhIMEWRkcmLMcQvx0OkAeMIZi2jHJOXxK9ZqVJ+A+Z6knw=="
},
"arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -7665,6 +7856,11 @@
"ieee754": "^1.1.13"
}
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -8069,6 +8265,14 @@
"safer-buffer": "^2.1.0"
}
},
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -8198,6 +8402,11 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-text-encoding": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
"integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
},
"feedparser": {
"version": "2.2.10",
"resolved": "https://registry.npmjs.org/feedparser/-/feedparser-2.2.10.tgz",
@@ -8340,6 +8549,26 @@
"wide-align": "^1.1.2"
}
},
"gaxios": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.0.1.tgz",
"integrity": "sha512-keK47BGKHyyOVQxgcUaSaFvr3ehZYAlvhvpHXy0YB2itzZef+GqZR8TBsfVRWghdwlKrYsn+8L8i3eblF7Oviw==",
"requires": {
"extend": "^3.0.2",
"https-proxy-agent": "^5.0.0",
"is-stream": "^2.0.0",
"node-fetch": "^2.6.7"
}
},
"gcp-metadata": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.0.0.tgz",
"integrity": "sha512-gfwuX3yA3nNsHSWUL4KG90UulNiq922Ukj3wLTrcnX33BB7PwB1o0ubR8KVvXu9nJH+P5w1j2SQSNNqto+H0DA==",
"requires": {
"gaxios": "^5.0.0",
"json-bigint": "^1.0.0"
}
},
"get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@@ -8371,12 +8600,75 @@
"path-is-absolute": "^1.0.0"
}
},
"google-auth-library": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.5.1.tgz",
"integrity": "sha512-7jNMDRhenfw2HLfL9m0ZP/Jw5hzXygfSprzBdypG3rZ+q2gIUbVC/osrFB7y/Z5dkrUr1mnLoDNlerF+p6VXZA==",
"requires": {
"arrify": "^2.0.0",
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
"fast-text-encoding": "^1.0.0",
"gaxios": "^5.0.0",
"gcp-metadata": "^5.0.0",
"gtoken": "^6.1.0",
"jws": "^4.0.0",
"lru-cache": "^6.0.0"
}
},
"google-p12-pem": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz",
"integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==",
"requires": {
"node-forge": "^1.3.1"
}
},
"googleapis": {
"version": "107.0.0",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-107.0.0.tgz",
"integrity": "sha512-emMvsOEPvE9/DxrOVCMblQzKAhaar37c5JPAqYXoo+hxPpzFefkpN5ayIJFgatDpUWCSMvWtP3CcEWfFhFA7QA==",
"requires": {
"google-auth-library": "^8.0.2",
"googleapis-common": "^6.0.0"
}
},
"googleapis-common": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.3.tgz",
"integrity": "sha512-Xyb4FsQ6PQDu4tAE/M/ev4yzZhFe2Gc7+rKmuCX2ZGk1ajBKbafsGlVYpmzGqQOT93BRDe8DiTmQb6YSkbICrA==",
"requires": {
"extend": "^3.0.2",
"gaxios": "^5.0.1",
"google-auth-library": "^8.0.2",
"qs": "^6.7.0",
"url-template": "^2.0.8",
"uuid": "^9.0.0"
},
"dependencies": {
"uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
}
}
},
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"optional": true
},
"gtoken": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz",
"integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==",
"requires": {
"gaxios": "^5.0.1",
"google-p12-pem": "^4.0.0",
"jws": "^4.0.0"
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -8618,6 +8910,11 @@
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
"optional": true
},
"is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -8651,6 +8948,14 @@
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"json-bigint": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
"requires": {
"bignumber.js": "^9.0.0"
}
},
"json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
@@ -8682,6 +8987,25 @@
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
"integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg=="
},
"jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
"requires": {
"jwa": "^2.0.0",
"safe-buffer": "^5.0.1"
}
},
"kareem": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz",
@@ -9142,6 +9466,11 @@
}
}
},
"node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
},
"node-gyp": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
@@ -11813,6 +12142,11 @@
"punycode": "^2.1.0"
}
},
"url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
"integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
},
"urljoin": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/urljoin/-/urljoin-0.1.5.tgz",
+2 -1
View File
@@ -2,7 +2,7 @@
"dependencies": {
"@alpacahq/alpaca-trade-api": "^2.16.1",
"@discordjs/opus": "github:discordjs/opus",
"@discordjs/rest": "^1.0.1",
"@discordjs/rest": "^1.1.0",
"@discordjs/voice": "^0.8.0",
"@napi-rs/canvas": "^0.1.22",
"apt": "^0.0.2",
@@ -22,6 +22,7 @@
"feedparser": "^2.2.10",
"ffmpeg": "^0.0.4",
"ffmpeg-static": "^5.0.0",
"googleapis": "^107.0.0",
"hastebin-gen": "^2.0.5",
"html-entities": "^2.3.3",
"libsodium-wrappers": "^0.7.10",
+83
View File
@@ -0,0 +1,83 @@
const {Client, Constants} = require('discord.js');
/**
* Registers all slash commands
* @param {Client} bot
*/
function registerCommands(bot) {
const commands = bot.application.commands;
/*
val: {
name: 'code',
description: "See where Selmer bot's code is stored! (you can also use _!repo_)",
execute: [Function: execute]
},
key: code
*/
bot.commands.forEach((val, key) => {
if (val.options && val.name != 'econ') {
if (val.isDM) {
commands.create({
name: val.name,
description: val.description,
options: val.options,
dm_permission: true,
});
} else {
commands.create({
name: val.name,
description: val.description,
options: val.options,
dm_permission: false,
});
}
} else {
// console.log(val, key);
console.log(key);
}
});
//Create the "econ" commands
const econList = ["buy", 'shop', 'work', 'rank', 'inventory', 'balance', 'sell'];
const econMain = require('./commands/db/econSlashOptions.js');
econList.forEach((commandName) => {
const command = econMain[`${commandName}`];
commands.create({
name: commandName,
description: command.description,
options: command.options || [],
dm_permission: false,
});
});
//Create the moderation commands
//NOTE: The user needs to have kicking or banning permissions to use these
const modList = ['lock', 'unlock', 'kick', 'ban', 'unban', 'mute', 'unmute'];
for (let i = 0; i < modList.length; i++) {
const opts = [
{name: "user", description: `The user to ${modList[i]}`, type: Constants.ApplicationCommandOptionTypes.USER, required: true},
{name: "reason", description: "Why?", type: Constants.ApplicationCommandOptionTypes.STRING, required: false}
];
commands.create({
name: modList[i],
description: `${modList[i]} a user`,
options: opts,
dm_permission: false,
default_member_permissions: 6,
});
// .then((comm) => {
// comm.setDefaultMemberPermissions(Discord.PermissionFlagsBits.KickMembers | Discord.PermissionFlagsBits.BanMembers);
// });
}
}
module.exports = { registerCommands }
+10 -10
View File
@@ -5,7 +5,7 @@ var FeedParser = require('feedparser');
const fetch = require('node-fetch');
const { VoiceConnectionStatus, AudioPlayerStatus, createAudioPlayer, StreamType, joinVoiceChannel, createAudioResource, getVoiceConnection } = require('@discordjs/voice');
const play = require('play-dl');
const { addComplaintButton } = require('../dev only/submitcomplaint');
const { addComplaintButton } = require('../../commands/dev only/spam_collection.js');
const hastebin = require("hastebin-gen");
const { simpleCast } = require('./simplecast.js')
@@ -137,11 +137,12 @@ function playAudio(bot, message, user, obj) {
async function getAndFormatRSS(bot, message, user, inp) {
message.reply(inp).catch((err) => { message.channel.send(inp); console.error(err); });
var req = fetch(inp)
const feedparser = new FeedParser();
req.then(function (res) {
if (res.status !== 200) {
throw new Error('Bad status code');
}
@@ -172,14 +173,15 @@ async function getAndFormatRSS(bot, message, user, inp) {
i ++;
if (i >= 100) { break; }
}
})
});
feedparser.addListener('end', () => {
const item = items[Math.round(Math.random() * items.length)];
// return console.log(item);
if (inp.indexOf('simplecast') != -1) {
var s = new simpleCast(item, inp);
s.audioLink = 'https://download.samplelib.com/mp3/sample-15s.mp3';
// s.audioLink = 'https://download.samplelib.com/mp3/sample-15s.mp3';
playAudio(bot, message, user, s);
}
});
@@ -314,9 +316,7 @@ module.exports = {
/*
REMOVED
"ABC": "https://abcnews.go.com/abcnews/topstories"
"FBI": "https://www.fbi.gov/feeds/national-press-releases/rss.xml" (Uhhhh......maybe I should't use this one.....)
REMOVED
"ABC": "https://abcnews.go.com/abcnews/topstories"
"FBI": "https://www.fbi.gov/feeds/national-press-releases/rss.xml" (Uhhhh......maybe I should't use this one.....)
*/