getting rid of the original sharpbot commands directory

This commit is contained in:
rhearmas 2019-12-22 22:24:31 -05:00
parent c2e2d75bd5
commit 84bf62a692
65 changed files with 0 additions and 3665 deletions

View file

@ -1,42 +0,0 @@
const responses = [
'Unclear, ask again later',
'Soon',
'Yes',
'Absolutely!',
'Never',
'Magic 8-ball is currently unavailable, please leave a message after the tone. \\*beep\\*',
'When you are ready',
'Hopefully',
'Hopefully not',
'Oh my, why would you even ask that?',
'What kind of a question is that?',
'Over my dead body!',
'Haha, funny joke'
];
function randomItem(array) {
return array[Math.floor(Math.random() * array.length)];
}
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'Please specify something to ask of the magic 8-ball!';
}
let response = randomItem(responses);
const query = args.join(' ');
if (query.indexOf('ipodtouch0218') > -1 || query.indexOf('233360087979130882') > -1) {
response = 'HAH';
}
msg.edit(`${query} :8ball: | **${response}**`);
};
exports.info = {
name: '8ball',
usage: '8ball <question>',
description: 'Asks the magic 8-ball a question'
};

View file

@ -1,24 +0,0 @@
exports.run = (bot, msg, args) => {
let parsed = bot.utils.parseArgs(args, 'd:');
if (parsed.leftover.length < 1) {
throw 'Please provide some emojis to use!';
}
let frames = parsed.leftover;
let content = frames.join(' ');
if (content.indexOf('|') > -1) {
frames = content.split('|');
}
let delay = isNaN(parsed.options.d) ? 250 : parsed.options.d;
bot.utils.playAnimation(msg, delay, frames);
};
exports.info = {
name: 'anim',
usage: 'anim [-d <delay>] <emoji> [emoji2] [...]',
description: '"Animates" a series of emojis'
};

View file

@ -1,30 +0,0 @@
const got = require('got');
function makeCommand(type, url, transformer) {
return {
run: async (bot, msg) => {
msg.edit(':arrows_counterclockwise:');
const { body } = await got(url);
let file;
try {
file = transformer(body);
} catch (ignore) {
return msg.error('Failed to transform image URL!');
}
msg.delete();
msg.channel.send({ files: [file] });
},
info: {
name: type,
usage: type,
description: `Sends a random ${type} image`
}
};
}
module.exports = [
makeCommand('cat', 'http://thecatapi.com/api/images/get?format=xml', body => /<url>(.+?)<\/url>/.exec(body)[1]),
makeCommand('dog', 'http://random.dog/woof', body => `http://random.dog/${body}`)
];

View file

@ -1,21 +0,0 @@
const got = require('got');
exports.run = async (bot, msg) => {
await msg.edit(':arrows_counterclockwise:');
const { body } = await got('http://belikebill.azurewebsites.net/billgen-API.php?default=1', { encoding: null });
await msg.channel.send({
file: {
attachment: body,
name: 'bill.jpg'
}
});
msg.delete();
};
exports.info = {
name: 'bill',
usage: 'bill',
description: 'Be like Bill!'
};

View file

@ -1,46 +0,0 @@
exports.methods = {
encode: input => {
return input.toString().split('')
.map(c => c.charCodeAt(0).toString(2));
},
decode: input => {
let _input = typeof input === 'string' ? input.split(' ') : input;
return _input.map(c => parseInt(c, 2))
.map(c => String.fromCharCode(c))
.join('');
}
};
exports.run = (bot, msg, args) => {
if (args.length < 2) {
throw `Do \`${bot.config.prefix}help binary\` to see how to use this.`;
}
let input = args.slice(1).join(' ');
if (args[0].match(/^enc(ode(Text)?)?$/i)) {
msg.edit(this.methods.encode(input).join(' '));
} else if (args[0].match(/^dec(ode(Text)?)?$/i)) {
msg.edit(this.methods.decode(input));
} else if (args[0].match(/^decToBin$/i)) {
if (isNaN(input)) {
throw 'Input must be a number!';
}
msg.edit(parseInt(input).toString(2));
} else if (args[0].match(/^binToDec$/i)) {
if (isNaN(input)) {
throw 'Input must be a number!';
}
msg.edit(parseInt(input, 2));
} else {
throw `Unknown sub command: \`${args[0]}\``;
}
};
exports.info = {
name: 'binary',
usage: 'binary <encodeText|decodeText|decToBin|binToDec> <input>',
description: 'Convert your input to/from binary'
};

View file

@ -1,15 +0,0 @@
const randomizeCase = word => word.split('').map(c => Math.random() > 0.5 ? c.toUpperCase() : c.toLowerCase()).join('');
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide some text to clapify';
}
msg.edit(args.map(randomizeCase).join(':clap:'));
};
exports.info = {
name: 'clap',
usage: 'clap <text>',
description: 'Clapifies your text'
};

View file

@ -1,59 +0,0 @@
exports.run = async (bot, msg, args) => {
const parsedArgs = bot.utils.parseArgs(args, ['d:', 's:']);
if (parsedArgs.leftover.length < 1) {
throw 'Please provide a secret message';
}
let message = parsedArgs.leftover.join(' ');
let delay = isNaN(parsedArgs.options.d) ? 5000 : parseInt(parsedArgs.options.d);
delay = (delay < 100) ? 100 : delay;
const style = (typeof parsedArgs.options.s === 'string') ? parsedArgs.options.s : 'plain';
msg.delete();
switch (style) {
case 'embed':
message = {
embed: bot.utils.embed(
`This message self-destructs in ${delay / 1000} seconds.`,
message,
[],
{
inline: true,
footer: 'Secret Message'
}
)
};
break;
case 'inline':
message = `*This message self-destructs in ${delay / 1000} seconds.*\n${message}`;
break;
case 'code':
message = `*This message self-destructs in ${delay / 1000} seconds.*\n\`\`\`${message}\`\`\``;
break;
}
(await msg.channel.send(message)).delete(delay);
};
exports.info = {
name: 'destruct',
usage: 'destruct [-d delay in ms] [-s <embed|inline|code|plain>] <message>',
description: 'creates a self-destructing message',
options: [
{
name: '-d',
usage: '-d <delay in ms>',
description: 'Sets the time (in ms) for the message to be deleted. (Default: 5 seconds)'
},
{
name: '-s',
usage: '-s <embed|inline|code|plain>',
description: 'Sets the message style (default: plain)'
}
],
credits: '<@140541588915879936>' // Doxylamin#4539
};

View file

@ -1,40 +0,0 @@
const mapping = {
' ': ' ',
'0': ':zero:',
'1': ':one:',
'2': ':two:',
'3': ':three:',
'4': ':four:',
'5': ':five:',
'6': ':six:',
'7': ':seven:',
'8': ':eight:',
'9': ':nine:',
'!': ':grey_exclamation:',
'?': ':grey_question:',
'#': ':hash:',
'*': ':asterisk:'
};
'abcdefghijklmnopqrstuvwxyz'.split('').forEach(c => {
mapping[c] = mapping[c.toUpperCase()] = ` :regional_indicator_${c}:`;
});
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide some text to fanceh-fy!';
}
msg.edit(
args.join(' ')
.split('')
.map(c => mapping[c] || c)
.join('')
);
};
exports.info = {
name: 'fanceh',
usage: 'fanceh <text>',
description: 'Renders text in big emoji letters'
};

View file

@ -1,52 +0,0 @@
const figlet = require('figlet');
exports.run = (bot, msg, args) => {
// -l -- List all fonts
// -f <font> -- Set font
const parsed = bot.utils.parseArgs(args, ['l', 'f:']);
if (parsed.options.l) {
bot.utils.textUpload(figlet.fontsSync().join('\n')).then(({ url }) => {
if (!url) {
return msg.error('Failed to upload fonts list!');
}
msg.edit({
embed: bot.utils.embed('Available Fonts', `A list of available fonts can be found [here](${url}).`)
}).then(m => m.delete(5000));
});
return;
}
if (parsed.leftover.length < 1) {
throw 'You must provide some text to render!';
}
const options = {};
if (parsed.options.f) {
options.font = parsed.options.f;
}
msg.delete();
const input = parsed.leftover.join(' ');
msg.channel.send(`\`\`\`\n${figlet.textSync(input, options)}\n\`\`\``);
};
exports.info = {
name: 'figlet',
usage: 'figlet <text>',
description: 'Renders fancy ASCII text',
options: [
{
name: '-f',
usage: '-f <font>',
description: 'Sets the font to use'
},
{
name: '-l',
description: 'Lists all available fonts'
}
]
};

View file

@ -1,22 +0,0 @@
const mapping = '¡"#$%⅋,)(*+\'-˙/0ƖᄅƐㄣϛ9ㄥ86:;<=>?@∀qƆpƎℲפHIſʞ˥WNOԀQɹS┴∩ΛMX⅄Z[/]^_`ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz{|}~';
// Start with the character '!'
const OFFSET = '!'.charCodeAt(0);
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide text to flip!';
}
msg.edit(
args.join(' ').split('')
.map(c => c.charCodeAt(0) - OFFSET)
.map(c => mapping[c] || ' ')
.reverse().join('')
);
};
exports.info = {
name: 'fliptext',
usage: 'fliptext <text>',
description: 'Flips your text!'
};

View file

@ -1,29 +0,0 @@
const got = require('got');
// Public API key provided by Giphy for anyone to use.
const API_KEY = 'dc6zaTOxFJmzC';
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide something to search for!';
}
const res = await got(`http://api.giphy.com/v1/gifs/random?api_key=${API_KEY}&tag=${encodeURIComponent(args.join(' '))}`, { json: true });
if (!res || !res.body || !res.body.data) {
throw 'Failed to find a GIF that matched your query!';
}
msg.delete();
msg.channel.send({
embed: bot.utils.embed('', '', [], { image: res.body.data.image_url })
});
};
// async function findRandom(query) {}
exports.info = {
name: 'gif',
usage: 'gif <query>',
description: 'Searches Giphy for GIFs'
};

View file

@ -1,12 +0,0 @@
exports.run = function(bot, msg, args) {
if (args.length === 0) {
throw 'You must input text to be transformed.';
}
msg.edit(args.map(arg => arg[0].toUpperCase() + arg.slice(1).toLowerCase()).join(' '));
};
exports.info = {
name: 'initial',
usage: 'initial <text>',
description: 'Transforms the text you input into Initial Caps'
};

View file

@ -1,34 +0,0 @@
exports.run = function (bot, msg, args) {
if (args.length < 1) {
throw 'Please provide an emoji to enlarge.';
}
if (args[0].charCodeAt(0) >= 55296) {
throw 'Cannot enlarge built-in discord emoji.';
}
const match = args[0].match(/<:[a-zA-Z0-9_-]+:(\d{18})>/);
if (!match || !match[1]) {
throw 'Please provide a valid emoji.';
}
const emoji = bot.emojis.get(match[1]);
if (!emoji) {
throw 'That emoji could not be identified!';
}
msg.delete();
msg.channel.send({
files: [
emoji.url
]
});
};
exports.info = {
name: 'jumbo',
usage: 'jumbo <emoji>',
description: 'Enlarges emojis!'
};

View file

@ -1,107 +0,0 @@
/*
Generating the inverse replacements isnt insanely expensive,
but I feel bad repeating an O(n) operation on every call of run
*/
let _inverseReplacementsCached = null;
const getInverseReplacements = replacements => {
if (_inverseReplacementsCached) {
return _inverseReplacementsCached;
}
const inverseReplacements = new Map();
Object.keys(replacements)
.map(letter => {
replacements[letter].forEach(replacement => {
inverseReplacements.set(new RegExp(global.utils.quoteRegex(replacement), 'gi'), letter);
});
});
_inverseReplacementsCached = inverseReplacements;
return inverseReplacements;
};
exports.run = function (bot, message, args) {
const parsedArgs = client.parseArgs(args, ['e', 't']);
if (parsedArgs.leftover.length < 1) {
throw 'Provide text to be leeted.';
}
let parsed;
if (parsedArgs.options.e) {
const extendedLeetReplacements = {
'a': ['4', '@', '/-\\', 'Д'],
'b': ['ß'],
'c': ['¢', '©'],
'e': ['3', '€'],
'f': ['ph', 'ƒ'],
'g': ['6'],
'i': ['1', '!'],
'l': ['7'],
'n': ['И', 'ท'],
'q': ['Ø'],
'r': ['®', 'Я'],
's': ['5', '$', '§'],
't': ['†'],
'u': ['|_|', 'µ', 'บ'],
'v': ['\\/'],
'w': ['\\/\\/', 'VV', 'Ш', 'พ'],
'x': ['Ж', '×'],
'y': ['¥']
};
const inverseReplacements = getInverseReplacements(extendedLeetReplacements);
if (parsedArgs.options.t) {
parsed = parsedArgs.leftover.join(' ');
for (let [replacement, origValue] of inverseReplacements) {
parsed = parsed.replace(replacement, origValue);
}
} else {
parsed = parsedArgs.leftover
.join(' ')
.replace(/[a-z]/gi, str => {
let selection = bot.utils.randomSelection(extendedLeetReplacements[str.toLowerCase()] || [str]);
selection = bot.utils.quoteRegex(selection);
return selection;
});
}
} else {
const simpleLeetReplacements = '4BCD3F6H1JKLMN0PQR57';
if (parsedArgs.options.t) {
parsed = parsedArgs.leftover.join(' ').replace(/[a-z0-9]/g, function (a) {
let foundInReplacements = simpleLeetReplacements.indexOf(a);
if (foundInReplacements === -1) {
return a;
}
return String.fromCharCode(97 + foundInReplacements);
});
} else {
parsed = parsedArgs.leftover.join(' ').replace(/[a-z]/g, function f(a) {
return simpleLeetReplacements[parseInt(a, 36) - 10] || a.replace(/[a-t]/gi, f);
}).toLowerCase();
}
}
message.delete();
message.channel.send(parsed);
};
exports.info = {
name: 'leet',
usage: 'leet <text>',
description: 'Talk like true gamers',
options: [
{
name: '-e',
usage: '-e',
description: 'Use extended l33t $p3@k'
},
{
name: '-t',
usage: '-t',
description: 'Translate from leet speak into English'
}
]
};

View file

@ -1,120 +0,0 @@
const got = require('got');
let templates = [];
function getMeme(name) {
return templates.find(m => m.name.toLowerCase() === name.toLowerCase());
}
function cleanInput(input) {
if (!input) return '';
return input.replace(/"/g, '\'\'').replace(/#/g, '~h')
.replace(/-/g, '--').replace(/_/g, '__')
.replace(/ /g, '_').replace(/\?/g, '~q')
.replace(/%/g, '~p').replace(/\//g, '~s');
}
exports.init = () => {
got('https://memegen.link/templates/').then(res => {
let data = JSON.parse(res.body);
templates = [];
let promises = [];
for (let key in data) {
promises.push(_loadMeme(data[key]));
}
Promise.all(promises).then(() => {
templates = templates.filter(e => !!e);
templates.sort((a, b) => a.name.localeCompare(b.name));
}).catch(console.error);
}).catch(console.error);
function _loadMeme(url) {
return got(url).then(res => {
let singleData = JSON.parse(res.body);
templates.push({
name: url.replace(/https:\/\/memegen\.link\/api\/templates\/(.*)/, '$1'),
url: url.replace('/api/templates', ''),
styles: singleData.styles
});
});
}
};
exports.run = async (bot, msg, args) => {
if (templates.length < 1) {
throw 'The memes haven\'t loaded yet!';
}
if (/^(h(elp)?|\?)$/i.test(args[0])) {
return bot.commands.get('help').run(bot, msg, 'meme');
}
if (/^(ls|list|s(earch)?)$/i.test(args[0])) {
msg.delete();
return (await msg.channel.send({
embed: bot.utils.embed('Available Memes', '*This message will vanish in 30 seconds*\n\n' + templates.map(meme => `- \`${meme.name}\``).join('\n'))
})).delete(30000);
}
if (/^(i(nf(o)?)?)$/i.test(args[0])) {
if (args.length < 2) {
throw 'You must provide a meme to get info about!';
}
let info = getMeme(args[1]);
if (!info) {
throw `That is not a valid meme! Do \`${bot.config.prefix}${this.info.name} list\` to see available memes.`;
}
msg.delete();
return (await msg.channel.send({
embed: bot.utils.embed(`\`${info.name}\``, `Styles: ${info.styles && info.styles.length > 1 ? info.styles.map(s => `\n- \`${s}\``).join('') : 'None'}`)
})).delete(15000);
}
let input = args.join(' ');
let parts = input.split('|').map(p => p.trim());
if (parts.length < 3) {
throw `No message was provided! Do \`${bot.config.prefix}help ${this.info.name}\` for info on how to use this.`;
}
let meme = getMeme(args[0]);
if (!meme) {
throw `That is not a valid meme! Do \`${bot.config.prefix}${this.info.name} list\` to see available memes.`;
}
let topText = cleanInput(parts[1]);
let bottomText = cleanInput(parts[2]);
if (!topText || !bottomText) {
throw 'Empty message!';
}
let url = `${meme.url}/${cleanInput(parts[1])}/${cleanInput(parts[2])}.jpg`;
if (parts[3]) url += `?alt=${encodeURIComponent(parts[3])}`;
await msg.edit(':arrows_counterclockwise:');
await msg.channel.send({
files: [
{
attachment: url,
name: parts[0] + '.jpg'
}
]
});
msg.delete();
};
exports.info = {
name: 'meme',
usage: 'meme list | info <name> | [<name> | <line 1> | <line 2> | [style]]',
description: 'Helps you generate meme images with custom text',
examples: [
'meme info sad-biden',
'meme facepalm | please, oh please | rtfm',
'meme sad-biden | sad joe biden | doesn\'t have discord | scowl'
]
};

View file

@ -1,12 +0,0 @@
exports.run = function (bot, msg, args) {
if (args.length < 1) {
throw 'You must input text to be reversed!';
}
msg.edit(args.join(' ').split('').reverse().join(''));
};
exports.info = {
name: 'reverse',
usage: 'reverse <text>',
description: 'Reverses the text you input'
};

View file

@ -1,41 +0,0 @@
const Roll = require('roll');
const roller = new Roll();
exports.run = function (bot, msg, args) {
if (args.length < 1) {
throw 'You must specify in dice notation (XdY)';
}
let reason = '';
let footer = '';
footer += `:game_die: **${args[0]}**`;
if (args.length > 1) {
reason = args.splice(1).join(' ');
footer += ` | ${reason}`;
}
let results = roller.roll(args[0]);
msg.delete();
let embed = bot.utils.embed(
`Total: ${results.result}`,
`${[].concat.apply([], results.rolled).join(', ').substr(0, 1800)}`,
[
{
name: '\u200b',
value: footer
}
]
);
msg.channel.send({ embed });
};
exports.info = {
name: 'roll',
usage: 'roll XdY <reason>',
description: 'rolls X dice with Y sides. Supports standard dice notation',
credits: '<@136641861073764352>' // Abyss#0473
};

View file

@ -1,18 +0,0 @@
exports.run = function (bot, msg) {
if (msg.mentions.users.size < 1) {
throw '@mention some people to shoot!';
}
let output = msg.mentions.users.map(m => `**${m}** :gun:`).join('\n');
msg.delete();
msg.channel.send({
embed: bot.utils.embed(`${bot.user.username} is on a killing spree!`, output)
});
};
exports.info = {
name: 'shoot',
usage: 'shoot <user>',
description: 'Shoots yer friendz!'
};

View file

@ -1,24 +0,0 @@
const ascii = `
\`\`\`
_______ _________ _________ , ,
/ | / | |
| | | | |
| | | | |
\\_____, | | _______, |________|
\\ | | | | |
| | | | | |
| | | | | |
______/ ____|____ \\________| | |
\u200b
\`\`\`
`;
exports.run = function (bot, msg) {
msg.edit(ascii);
};
exports.info = {
name: 'sigh',
usage: 'sigh',
description: 'Dramatic sigh text'
};

View file

@ -1,22 +0,0 @@
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide text to space out!';
}
let amount = 2;
if (!isNaN(args[0])) {
amount = parseInt(args[0]);
(amount < 1) && (amount = 1);
(amount > 15) && (amount = 15);
args = args.slice(1);
}
msg.edit(args.join(' '.repeat(amount / 2)).split('').join(' '.repeat(amount)));
};
exports.info = {
name: 'space',
usage: 'space [amount] <text>',
description: 'Spaces out text to look all dramatic n\' stuff'
};

View file

@ -1,57 +0,0 @@
const mappings = (function (object) {
let output = [];
for (let key in object) {
output.push({
regex: new RegExp(key, 'ig'),
replacement: object[key]
});
}
return output;
})({
a: '\u1D00',
b: '\u0299',
c: '\u1D04',
d: '\u1D05',
e: '\u1D07',
f: '\uA730',
g: '\u0262',
h: '\u029C',
i: '\u026A',
j: '\u1D0A',
k: '\u1D0B',
l: '\u029F',
m: '\u1D0D',
n: '\u0274',
o: '\u1D0F',
p: '\u1D18',
q: '\u0071',
r: '\u0280',
s: '\uA731',
t: '\u1D1B',
u: '\u1D1C',
v: '\u1D20',
w: '\u1D21',
x: '\u0078',
y: '\u028F',
z: '\u1D22'
});
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide some text to shrink!';
}
let output = args.join(' ');
mappings.forEach(replacer => output = output.replace(replacer.regex, replacer.replacement));
msg.delete();
msg.channel.send(output);
};
exports.info = {
name: 'tiny',
usage: 'tiny <text>',
description: 'Converts your text to tiny letters!'
};

View file

@ -1,52 +0,0 @@
const got = require('got');
exports.run = async (bot, msg, args) => {
let id;
if (args[0] === 'latest') {
id = (await getLatest()).num;
} else {
id = parseInt(args[0]);
if (isNaN(id)) {
id = await getRandom();
}
}
// Avoid the 404 page
while (id === 404) {
id = await getRandom();
}
const info = await getInfo(id);
msg.delete();
msg.channel.send({
embed: bot.utils.embed(`[${id}] ${info.title}`, '', [], {
image: info.img,
// Color of the XKCD website.
color: [150, 168, 199],
url: `http://xkcd.com/${id}`
}).setFooter(info.alt)
});
};
async function getInfo(id) {
return (await got(`http://xkcd.com/${id}/info.0.json`, { json: true })).body;
}
async function getLatest() {
return (await got('http://xkcd.com/info.0.json', { json: true })).body;
}
async function getRandom() {
const latest = await getLatest();
const max = latest.num;
return Math.floor(Math.random() * max);
}
exports.info = {
name: 'xkcd',
usage: 'xkcd [latest|<id>]',
description: 'Fetches random or specific XKCD comics'
};

View file

@ -1,67 +0,0 @@
const { RichEmbed } = require('discord.js');
const rgbToHSL = (red, green, blue) => {
let r = red / 255;
let g = green / 255;
let b = blue / 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
h = Math.round(h * 360);
s = Math.round(s * 100);
l = Math.round(l * 100);
return { hue: h, saturation: s, lightness: l };
};
const resolveColor = input => {
if (input.startsWith('#')) input = input.substr(1);
if (input.length === 3) input = input.split('').map(c => c + c).join('');
let hex = input;
let [red, green, blue] = [hex.substr(0, 2), hex.substr(2, 2), hex.substr(4, 2)]
.map(value => parseInt(value, 16));
let { hue, saturation, lightness } = rgbToHSL(red, green, blue);
return { hex, red, green, blue, hue, saturation, lightness };
};
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide a color!';
}
if (!/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(args[0])) {
throw 'The color must be in the format of `#RRGGBB` or `#RGB`!';
}
let color = resolveColor(args[0]);
msg.delete();
msg.channel.send({
embed: new RichEmbed()
.setDescription(`Hex: \`#${color.hex}\`\nRGB: \`${color.red}, ${color.green}, ${color.blue}\`\nHSL: \`${color.hue}, ${color.saturation}, ${color.lightness}\``)
.setImage(`http://placehold.it/500/${color.hex}/${color.hex}`)
.setColor(`${color.hex}`)
});
};
exports.info = {
name: 'color',
usage: 'color <hex>',
description: 'Shows information and a preview of a hex color'
};

View file

@ -1,53 +0,0 @@
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide an emoji to gather info on!';
}
if (args[0].charCodeAt(0) >= 55296) {
msg.delete();
return (await msg.channel.send({
embed: bot.utils.embed(args[0], 'Built-in **Discord** emoji.')
})).delete(15000);
}
const match = args[0].match(/<:[a-zA-Z0-9_-]+:(\d{18})>/);
if (!match || !match[1]) {
throw 'Please provide a valid emoji!';
}
const emoji = bot.emojis.get(match[1]);
if (!emoji) {
throw 'That emoji could not be identified.';
}
msg.delete();
(await msg.channel.send({
embed: bot.utils.embed('', '', [
{
name: 'Name',
value: emoji.name
},
{
name: 'From Guild',
value: emoji.guild.name
},
{
name: 'ID',
value: emoji.id
},
{
name: 'Download URL',
value: emoji.url
}
], { thumbnail: emoji.url })
})).delete(15000);
};
exports.info = {
name: 'emoji',
usage: 'emoji <emoji>',
description: 'Shows information about an emoji'
};

View file

@ -1,26 +0,0 @@
const oneLine = require('common-tags').oneLine;
exports.run = (bot, msg) => {
let servers = bot.guilds.array().sort((a, b) => b.memberCount - a.memberCount).map(guild => {
return {
name: guild.name,
value: oneLine`
${guild.memberCount} users,
${guild.channels.size} channels
`
};
});
for (let i = 0; i < servers.length / 20; i += 20) {
msg.edit('', {
embed: bot.utils.embed(`${bot.user.username}'s Servers`, '\u200b', servers.slice(i, i + 20), { inline: true })
});
}
};
exports.info = {
name: 'guilds',
usage: 'guilds',
description: 'Lists all guilds that you\'re a member of'
};

View file

@ -1,112 +0,0 @@
const stripIndents = require('common-tags').stripIndents;
exports.run = async (bot, msg, args) => {
let commands = [];
let title = 'Categories';
if (args.length > 0) {
if (/^category|type$/i.test(args[0])) {
if (args.length < 2) {
throw 'You must specify a category!';
}
commands = bot.commands.all(args[1]);
title = `${args[1]} Commands`;
} else if (/^all|full|every$/i.test(args[0])) {
commands = bot.commands.all();
title = 'All Commands';
} else {
let command = bot.commands.get(args[0]);
if (!command) {
throw `The command '${args[0]}' does not exist!`;
}
commands = [command];
title = `Help for \`${command.info.name}\``;
}
}
if (commands.length > 0) {
let fields = commands.filter(c => !c.info.hidden)
.sort((a, b) => a.info.name.localeCompare(b.info.name))
.map(c => getHelp(bot, c, commands.length === 1));
// Temporary workaround for the 2k char limit
let maxLength = 1900;
let messages = [];
while (fields.length > 0) {
let len = 0;
let i = 0;
while (len < maxLength) {
if (i >= fields.length) {
break;
}
let field = fields[i];
len += field.name.length + field.value.length;
if (len >= maxLength) {
break;
}
i++;
}
messages.push({ fields: fields.splice(0, i) });
}
msg.delete().catch(() => { });
messages.map(m => m.fields).forEach(async fields => {
(await msg.channel.send({
embed: bot.utils.embed(title, '_This message will self-destruct in 90 seconds._ :boom:', fields)
})).delete(90000);
});
} else {
let categories = bot.commands.categories().sort();
(await msg.edit({
embed: bot.utils.embed(title, stripIndents`
**Available categories:**
${categories.map(c => `- __${c}__`).join('\n')}
**Usage:**
Do \`${bot.config.prefix}help category <name>\` for a list of commands in a specific category.
Do \`${bot.config.prefix}help all\` for a list of every command available in this bot.
Do \`${bot.config.prefix}help <command>\` for **extended** command help and command options.`)
})).delete(15000);
}
};
const getHelp = (bot, command, single) => {
let description = stripIndents`
**Usage:** \`${bot.config.prefix}${command.info.usage || command.info.name}\`
**Description:** ${command.info.description || '<no description>'}
**Category:** __${command.info.category}__`;
if (command.info.credits)
description += `\n**Credits:** *${command.info.credits}*`;
if (single && command.info.examples)
description += `\n**Examples:**\n${command.info.examples.map(example => `\`${bot.config.prefix}${example}\``).join('\n')}`;
if (single && command.info.options instanceof Array) {
let options = command.info.options.map(option => {
return stripIndents`
**${option.name}**
*Usage:* \`${option.usage || option.name}\`
*Description:* ${option.description}
`;
});
description += `\n**Options:**\n\n${options.join('\n\n')}`;
}
return {
name: single ? '\u200b' : command.info.name,
value: description
};
};
exports.info = {
name: 'help',
usage: 'help all|[command]|[category <name>]',
description: 'Shows you help for all commands or just a single command'
};

View file

@ -1,39 +0,0 @@
const limitTo = (array, max, joiner) => array.slice(0, max).join(joiner) + (array.length <= max ? '' : '...');
const inGuild = (guild, user) => !!guild.members.find('id', user.id);
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide a name of a Discord server you are in.';
}
const query = args.join(' ').toLowerCase();
// Try to parse by Server Name fist or Server ID
const guild = bot.guilds.find(guild => guild.name.toLowerCase() === query || guild.id === query);
if (!guild) {
throw 'That guild could not be found!';
}
const mutual = bot.users.filter(user => inGuild(msg.guild, user) && inGuild(guild, user));
await msg.edit(':arrows_counterclockwise: Searching...');
const { url } = await bot.utils.textUpload(mutual.map(user => `- ${user.tag}`).join('\n'));
msg.delete();
(await msg.channel.send({
embed: bot.utils.embed(`Mutual members of ${guild.name}`, limitTo(mutual.array().map(user => user.tag), 25, ', '), [
{
name: 'Full List',
value: url
}
])
})).delete(30000);
};
exports.info = {
name: 'mutual',
usage: 'mutual <server>',
description: 'Finds users who are in a given server that you are in'
};

View file

@ -1,51 +0,0 @@
const got = require('got');
const cheerio = require('cheerio');
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide the username of a player.';
}
const username = args[0];
const uuid = await getUUID(username);
if (!uuid) {
throw 'That player could not be found.';
}
msg.delete();
return msg.channel.send({
embed: bot.utils.embed('', '', [
{
name: 'Username',
value: username
},
{
name: 'UUID',
value: `\`${uuid}\``
},
{
name: 'Skin',
value: `[Download](https://crafatar.com/skins/${uuid}.png)`
}
], { thumbnail: `https://crafatar.com/avatars/${uuid}.png?size=250&overlay=true` })
});
};
async function getUUID(username) {
const res = await got(`https://mcuuid.net/?q=${username}`);
const $ = cheerio.load(res.body);
const input = $('input')[1];
if (!input) {
return;
}
return input.attribs['value'];
}
exports.info = {
name: 'playerinfo',
usage: 'playerinfo <username>',
description: 'Shows information about a Minecraft player'
};

View file

@ -1,80 +0,0 @@
const dateFormat = require('dateformat');
const now = new Date();
dateFormat(now, 'dddd, mmmm dS, yyyy, h:MM:ss TT');
exports.run = async (bot, msg) => {
if (!msg.guild) {
throw 'This can only be used in a guild!';
}
const millis = new Date().getTime() - msg.guild.createdAt.getTime();
const days = millis / 1000 / 60 / 60 / 24;
const owner = msg.guild.owner.user || {};
const verificationLevels = ['None', 'Low', 'Medium', 'Insane', 'Extreme'];
let embed = bot.utils.embed(
`${msg.guild.name}`,
'***This message will dissappear in 60 seconds.***',
[
{
name: 'Created On',
value: `${dateFormat(msg.guild.createdAt)}`,
},
{
name: 'Days Since Creation',
value: `${days.toFixed(0)}`,
},
{
name: 'Default Channel',
value: `${msg.guild.defaultChannel}`,
},
{
name: 'Region',
value: `${msg.guild.region}`,
},
{
name: 'Member Count',
value: `${msg.guild.members.filter(m => m.presence.status !== 'offline').size} / ${msg.guild.memberCount}`,
},
{
name: 'Owner',
value: `${owner.username || 'None'}`,
},
{
name: 'Text Channels',
value: `${msg.guild.channels.filter(m => m.type === 'text').size}`,
},
{
name: 'Voice Channels',
value: `${msg.guild.channels.filter(m => m.type === 'voice').size}`,
},
{
name: 'Verification Level',
value: `${verificationLevels[msg.guild.verificationLevel]}`,
},
{
name: 'Roles',
value: `${msg.guild.roles.size}`,
},
],
{
inline: true,
footer: `Guild ID: ${msg.guild.id}`
}
);
if (msg.guild.iconURL != null) {
embed.setThumbnail(`${msg.guild.iconURL}`);
}
(await msg.edit({ embed })).delete(60000);
};
exports.info = {
name: 'serverinfo',
usage: 'serverinfo',
description: 'Shows info of the server you are in'
};

View file

@ -1,68 +0,0 @@
const formatTime = (time) => {
let seconds = time[0] + time[1] / 1e9;
let minutes = Math.floor(seconds / 60);
seconds = seconds % 60;
let hours = Math.floor(minutes / 60);
minutes = minutes % 60;
return `${hours.toFixed(0)}h ${minutes.toFixed(0)}m ${seconds.toFixed(0)}s`;
};
const activityTypes = [
'playing',
'streaming',
'listening to',
'watching',
];
exports.run = async (bot, msg) => {
const game = bot.user.presence.game || {};
(await msg.edit({
embed: bot.utils.embed('SharpBot Stats', '***This message will dissappear in 30 seconds.***', [
{
name: ':outbox_tray: Messages sent',
value: bot.managers.stats.get('messages-sent') || 0,
},
{
name: ':inbox_tray: Messages received',
value: bot.managers.stats.get('messages-received') || 0,
},
{
name: ':mailbox: Mentions',
value: bot.managers.stats.get('mentions') || 0
},
{
name: ':baby: Users',
value: `${bot.guilds.reduce((mem, g) => mem += g.memberCount, 0)}`,
},
{
name: ':desktop: Servers',
value: `${bot.guilds.size.toLocaleString()}`,
},
{
name: ':keyboard: Channels',
value: `${bot.channels.size.toLocaleString()}`,
},
{
name: ':thinking: RAM usage',
value: `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`,
},
{
name: ':stopwatch: Uptime',
value: formatTime(process.hrtime(bot.managers.stats.get('start-time')))
},
{
name: ':video_game: Game',
value: (game.name) ? `*${activityTypes[game.type]}* ${game.name} ${game.streaming ? `[(Streaming)](${game.url})` : ''}` : 'none'
}
], { inline: true })
})).delete(30000);
};
exports.info = {
name: 'stats',
usage: 'stats',
description: 'Shows you stats about SharpBot'
};

View file

@ -1,21 +0,0 @@
exports.run = function (bot, msg) {
const user = msg.mentions.users.first();
if (!user) {
throw 'Please mention a user.';
}
const delmsg = bot.deleted.get(user.id);
if (!delmsg) {
throw 'No recently deleted messages found';
}
bot.deleted.delete(user.id);
msg.edit(`Undeleted message of ${user.username} in ${delmsg.guild.name} | ${delmsg.channel.name}\n\`\`\`${delmsg.content}\`\`\``);
};
exports.info = {
name: 'undelete',
usage: 'undelete <mention of user>',
description: 'Undeletes messages'
};

View file

@ -1,84 +0,0 @@
const dateFormat = require('dateformat');
dateFormat('dddd, mmmm dS, yyyy, h:MM:ss TT');
exports.run = async (bot, msg) => {
//Makes sure command is sent in a guild
if (!msg.guild) {
throw 'This can only be used in a guild!';
}
//Makes sure user mentions a user to get info for
if (msg.mentions.users.size < 1) {
throw '@mention someone to find the info';
}
let user = msg.mentions.users.first();
let member = msg.guild.member(user);
if (!member) {
throw 'That member could not be found!';
}
//How long ago the account was created
const millisCreated = new Date().getTime() - user.createdAt.getTime();
const daysCreated = millisCreated / 1000 / 60 / 60 / 24;
//How long about the user joined the server
const millisJoined = new Date().getTime() - member.joinedAt.getTime();
const daysJoined = millisJoined / 1000 / 60 / 60 / 24;
// Slice off the first item (the @everyone)
let roles = member.roles.array().slice(1).sort((a, b) => a.comparePositionTo(b)).reverse().map(role => role.name);
if (roles.length < 1) roles = ['None'];
let embed = bot.utils.embed(
`${user.username}#${msg.mentions.users.first().discriminator}`,
'***This message will dissappear in 60 seconds.***',
[
{
name: 'Status',
value: `${user.presence.status[0].toUpperCase() + user.presence.status.slice(1)}`,
},
{
name: 'Game',
value: `${(user.presence.game && user.presence.game && user.presence.game.name) || 'Not playing a game.'}`,
},
{
name: 'Created On',
value: `${dateFormat(user.createdAt)}`,
},
{
name: 'Days Since Creation',
value: `${daysCreated.toFixed(0)}`,
},
{
name: 'Joined On',
value: `${dateFormat(member.joinedAt)}`,
},
{
name: 'Days Since Joining',
value: `${daysJoined.toFixed(0)}`,
},
{
name: 'Roles',
value: `${roles.join(', ')}`,
inline: false,
},
],
{
inline: true,
footer: `User ID: ${user.id}`,
thumbnail: user.displayAvatarURL
}
);
(await msg.edit({ embed })).delete(60000);
};
exports.info = {
name: 'userinfo',
usage: 'userinfo <user>',
description: 'Shows info about a user'
};

View file

@ -1,47 +0,0 @@
function hasRole(member, roleName) {
return member.roles.map(role => role.name.toLowerCase()).indexOf(roleName.toLowerCase()) > -1;
}
exports.run = async (bot, msg, args) => {
if (!msg.guild || !msg.guild.members) {
throw 'You must run this command from within a server.';
}
let members = msg.guild.members.array().sort((a, b) => a.user.username.localeCompare(b.user.username));
if (args.length > 0) {
members = members.filter(member => hasRole(member, args[0]));
}
if (members.length < 1) {
throw 'No members could be found.';
}
msg.delete();
let users = members.map(m => `${m.user}${(m.user.bot ? ' [BOT]' : '')}`);
const body = users.join('\n');
if (body.length < 2000) {
(await msg.channel.send({
embed: bot.utils.embed('', body)
})).delete(60000);
} else {
let raw = members.map(m => `${m.user.username}${m.user.bot ? ' [BOT]' : ''}`).join('\n');
const { url } = await bot.utils.textUpload(raw);
let trimmed = body.substr(0, 1500);
trimmed = trimmed.slice(0, trimmed.lastIndexOf('\n'));
msg.channel.send({
embed: bot.utils.embed('', trimmed, [{ name: 'Full list', value: url }])
});
}
};
exports.info = {
name: 'users',
usage: 'users [role]',
description: 'Lists all users on your current server'
};

View file

@ -1,31 +0,0 @@
function makeCommand(name, viewName, description, filter) {
return {
run: async (bot, msg, args) => {
let count = parseInt(args[0]) || 1;
msg.delete();
const messages = await msg.channel.fetchMessages({ limit: Math.min(count, 100), before: msg.id });
const deletable = messages.filter(message => filter(message, bot));
await Promise.all(
deletable.map(m => m.delete())
);
const deleted = deletable.size;
(await msg.channel.send(`:white_check_mark: ${viewName} \`${deletable.size}\` message${deleted === 1 ? '' : 's'}.`)).delete(2000);
},
info: {
name,
usage: `${name} [amount]`,
description
}
};
}
module.exports = [
makeCommand('purge', 'Purged', 'Deletes a certain number of messages', () => true),
makeCommand('prune', 'Pruned', 'Deletes a certain number of messages sent by you', (msg, bot) => msg.author.id === bot.user.id),
makeCommand('flush', 'Flushed', 'Deletes a certain number of messages sent by bots', msg => msg.author.bot)
];

View file

@ -1,58 +0,0 @@
exports.run = async (bot, msg, args) => {
let channel = msg.channel;
if (args.length < 1) {
throw 'You must provide a message ID';
}
if (!/^\d{18}$/.test(args[0])) {
throw 'You must provide a valid message ID.';
}
if (args[1] && /^<#\d{18}>$|^\d{18}$/.test(args[1])) {
channel = bot.channels.get(args[1].replace(/[<#>]/g, ''));
}
if (!channel) {
throw 'That channel could not be found!';
}
const messages = await channel.fetchMessages({ around: args[0], limit: 1 });
if (!messages || messages.size < 1) {
throw 'That message could not be found!';
}
let message = messages.first();
let options = {
timestamp: message.editedTimestamp || message.createdTimestamp,
footer: false
};
let attachment = message.attachments.first();
if (attachment && (attachment.width || attachment.height)) {
options.image = attachment.url;
}
let field = '';
if ((msg.guild || {}).id !== (channel.guild || {}).id) {
field = `**in ${(channel.guild || { name: 'DMs' }).name} <#${channel.id}>:**`;
} else if (channel.id !== msg.channel.id) {
field = `**in <#${channel.id}>:**`;
}
msg.delete();
msg.channel.send({
embed: bot.utils.embed('', field + '\n\n' + message.toString(), [], options)
.setAuthor(message.author.username, message.author.avatarURL)
});
};
exports.info = {
name: 'quote',
usage: 'quote <id> [#channel | channel ID]',
description: 'Quotes the message with the given ID and channel ID.'
};

View file

@ -1,48 +0,0 @@
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'You must specify what to search for!';
}
let query = args.join(' ');
await msg.edit(`:arrows_counterclockwise: Searching the last \`100\` messages for \`${query}\``);
const messages = await msg.channel.fetchMessages({ limit: 100, before: msg.id });
const results = messages.filter(it => it.cleanContent.toLowerCase().indexOf(query.toLowerCase()) != -1)
.sort((a, b) => (a.editedTimestamp || a.createdTimestamp) - (b.editedTimestamp || b.createdTimestamp));
if (results.length < 1) {
throw 'No results found.';
}
const output = results
.map(message => `${formatDate(message.createdAt)} ${message.author.username}: ${message.content}`)
.join('\n');
msg.delete();
bot.utils.sendLarge(
msg.channel,
output.replace(/`/g, '\u200b`'),
{
prefix: '```log\n',
suffix: '\n```',
delay: 10,
cutOn: '\n'
}
);
};
function formatDate(date) {
return `[${_(date.getDay())}/${_(date.getMonth())}/${_(date.getYear() - 100)}] [${_(date.getHours())}:${_(date.getMinutes())}:${_(date.getSeconds())}]`;
}
function _(number) {
return number < 10 ? '0' + number : '' + number;
}
exports.info = {
name: 'search',
usage: 'search <#> <text>',
description: 'Searches a number of messages for some text'
};

View file

@ -1,17 +0,0 @@
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide a prefix to set!';
}
const prefix = args.join(' ');
bot.managers.config.set('prefix', prefix);
// No point trying to delete this message, the bot will be
// rebooting before we have a chance to.
msg.edit('Prefix set, rebooting! :ok_hand:');
};
exports.info = {
name: 'prefix',
usage: 'prefix <new prefix>',
description: 'Sets the bot prefix'
};

View file

@ -1,68 +0,0 @@
const normalizeUrl = require('normalize-url');
exports.run = async (bot, msg, args) => {
let { leftover, options } = bot.utils.parseArgs(args, ['s:', 'w', 'l']);
if (leftover.length < 1) {
if (options.s) {
throw 'You must provide a game as well as a stream URL.';
}
bot.user.setActivity(null, {});
return msg.edit('Cleared your game! :ok_hand:').then(m => m.delete(3000));
}
let game = leftover.join(' ');
let stream = options.s;
let fields = [];
let activityOptions = { type: 'PLAYING' };
let activityFieldTitle = ':video_game: Game';
if (stream) {
stream = normalizeUrl(`twitch.tv/${stream}`);
activityOptions.url = stream;
activityOptions.type = 'STREAMING';
fields.push({ name: ':headphones: Stream URL', value: stream });
} else if (options.w) {
activityOptions.type = 'WATCHING';
activityFieldTitle = ':eyes: Watching';
} else if (options.l) {
activityOptions.type = 'LISTENING';
activityFieldTitle = ':sound: Listening to';
}
fields.unshift({ name: activityFieldTitle, value: game });
bot.user.setActivity(game, activityOptions);
msg.delete();
(await msg.channel.send({
embed: bot.utils.embed(':ok_hand: Game changed!', '', fields)
})).delete(5000);
};
exports.info = {
name: 'setgame',
usage: 'setgame <game>',
description: 'Sets your game (shows for other people)',
options: [
{
name: '-s',
usage: '-s <url>',
description: 'Sets your streaming URL to http://twitch.tv/<url>'
},
{
name: '-w',
description: 'Sets your game prefix to **Watching**'
},
{
name: '-l',
description: 'Sets your game prefix to **Listening to**'
}
]
};

View file

@ -1,23 +0,0 @@
// This command has already been created.
exports.run = async (bot, msg) => {
const user = msg.mentions.users.first();
if (!user) {
throw 'Please mention the user who you want the avatar from.';
}
if (!user.avatarURL) {
throw 'That user does not have an avatar.';
}
msg.delete();
(await msg.channel.send({
embed: bot.utils.embed(`${user.username}'s Avatar`, `[Download](${user.avatarURL})`, [], { image: user.avatarURL })
})).delete(30000);
};
exports.info = {
name: 'avatar',
usage: 'avatar <user>',
description: 'Gives you the avatar of a user'
};

View file

@ -1,35 +0,0 @@
// This command has already been created.
const math = require('math-expression-evaluator');
const stripIndents = require('common-tags').stripIndents;
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide a equation to be solved on the calculator';
}
const question = args.join(' ');
let answer;
try {
answer = math.eval(question);
} catch (err) {
throw `Invalid math equation: ${err}`;
}
msg.delete();
msg.channel.send({
embed: bot.utils.embed('', stripIndents`
**Equation:**\n\`\`\`\n${question}\n\`\`\`
**Answer:**\n\`\`\`\n${answer}\n\`\`\`
`)
});
};
exports.info = {
name: 'calculate',
usage: 'calculate <equation>',
aliases: ['calc', 'math'],
description: 'Calculates any math equation',
credits: 'Carbowix',
};

View file

@ -1,55 +0,0 @@
// This command has already been created.
const webdict = require('webdict');
const makeCommand = method => {
return (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide a word to search!';
}
const parsed = bot.utils.parseArgs(args, ['e']);
const word = parsed.leftover.join(' ');
webdict(method, word).then(res => {
let result;
if (!res || !res.definition || !res.definition[0]) {
result = 'No results found.';
} else {
result = res.definition[0];
}
if (parsed.options.e) {
msg.edit(result);
return;
}
msg.delete();
msg.channel.send({
embed: bot.utils.embed(`:book: ${word}`, result)
});
});
};
};
module.exports = [
{
run: makeCommand('dictionary'),
info: {
name: 'dictionary',
aliases: ['dict'],
usage: 'dictionary <word>',
description: 'Looks a word up in the dictionary.',
credits: 'NITEHAWK'
}
},
{
run: makeCommand('urbandictionary'),
info: {
name: 'urban',
usage: 'urban <word>',
description: 'Looks a word up in the urban dictionary.',
credits: 'NITEHAWK'
}
}
];

View file

@ -1,95 +0,0 @@
// This command has already been completed.
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must specify something to embed!';
}
let parsed = bot.utils.parseArgs(args, ['f', 'ft:', 'd', 't:', 'c:', 'r', 'i:', 'a:', 'th:']);
let color = parsed.options.c;
if (parsed.options.r && msg.guild && msg.guild.members) {
let member = msg.guild.members.get(msg.author.id);
if (member) {
color = member.highestRole.hexColor;
}
}
if (color) {
if (!color.startsWith('#')) {
color = `#${color}`;
}
if (!/^#[a-fA-F0-9]{6}$/.test(color)) {
throw `Invalid color: \`${color}\`. Please use valid hex format (\`#RRGGBB\`)`;
}
}
msg.delete();
msg.channel.send({
embed: bot.utils.embed(parsed.options.t || '', parsed.leftover.join(' '), [], {
footer: parsed.options.f || parsed.options.ft,
timestamp: parsed.options.d,
color,
image: parsed.options.i,
author: parsed.options.a,
thumbnail: parsed.options.th
})
});
};
exports.info = {
name: 'embed',
usage: 'embed [text]',
description: 'Sends a message via embeds',
examples: [
'embed Hello world!',
'embed -c #ff0000 Red is my favorite color :heart:',
'embed -r -t "Welcome to my server!" I hope you enjoy your time here.'
],
options: [
{
name: '-f',
description: 'Shows the footer'
},
{
name: '-ft',
usage: '-ft <text>',
description: 'Sets the footer text (use quotes for multiple words)'
},
{
name: '-d',
usage: '-d',
description: 'Enables the timestamp (date) in the footer'
},
{
name: '-t',
usage: '-t <text>',
description: 'Sets the embed title (use quotes for multiple words)'
},
{
name: '-r',
description: 'Uses your role color for the embed color'
},
{
name: '-c',
usage: '-c <color>',
description: 'Sets a hex color for the embed in the format of `#RRGGBB`'
},
{
name: '-i',
usage: '-i <url>',
description: 'Sets an image for the embed'
},
{
name: '-a',
usage: '-a <name>',
description: 'Sets the author of the embed'
},
{
name: '-th',
usage: '-th <url>',
description: 'Sets a thumbnail for the embed'
}
]
};

View file

@ -1,99 +0,0 @@
const stripIndents = require('common-tags').stripIndents;
exports.run = async (bot, msg, args) => {
let parsed = bot.utils.parseArgs(args, ['l:', 'i', 'q']);
let lang = parsed.options.l || '';
let code = parsed.leftover.join(' ');
let output;
try {
output = await eval(code);
} catch (err) {
let message = err;
if (err && err.response && err.response.body && err.response.body.message) {
message = err.response.body.message;
}
return errorHandler(msg, bot, code, `${message}`);
}
msg.delete();
if (parsed.options.q) {
return;
}
if (typeof output !== 'string') {
output = require('util').inspect(output);
}
if (!lang) {
lang = 'javascript';
}
output = clean(output).replace(new RegExp(bot.utils.quoteRegex(bot.token), 'g'), 'BOT_TOKEN');
const displayedOutput = output.length < 1500
? `\n\`\`\`${lang}\n${output}\n\`\`\``
: `\n${await tryUpload(bot, output)}\n`;
msg.channel.send({
embed: bot.utils.embed('', stripIndents`
**Input:**\n\`\`\`js\n${code}\n\`\`\`
**Output:**${displayedOutput}
`)
});
if (output.length > 1500 && parsed.options.i) {
bot.utils.sendLarge(msg.channel, output, {
prefix: '```' + lang + '\n',
suffix: '```',
cutOn: ',',
cutAfter: true
});
}
};
const tryUpload = async (bot, content) => {
const { url } = await bot.utils.textUpload(content);
if (!url) {
throw 'Failed to upload!';
}
return url;
};
const errorHandler = (msg, bot, code, err) => {
msg.delete();
msg.channel.send({
embed: bot.utils.embed('', `**Input:**\n\`\`\`js\n${code}\n\`\`\`\n:x: **Error!**\n\`\`\`xl\n${clean(err)}\n\`\`\``, [], {
color: '#ff0000'
})
}).then(m => m.delete(15000));
};
// Prevent @mentions, #channels or code blocks inside code blocks.
const clean = text => text.replace(/([`@#])/g, '$1\u200b');
exports.info = {
name: 'eval',
usage: 'eval <code>',
description: 'Evaluates arbitrary JavaScript',
options: [
{
name: '-l',
usage: '-l <lang>',
description: 'Sets the output code-block syntax language'
},
{
name: '-i',
usage: '-i',
description: 'Inline extra-long output in addition to uploading to hastebin'
},
{
name: '-q',
usage: '-q',
description: 'Does not print any output'
}
]
};

View file

@ -1,130 +0,0 @@
const { exec } = require('child_process');
const username = require('os').userInfo().username;
exports.run = async (bot, msg, args) => {
let parsed = bot.utils.parseArgs(args, ['r', 'd', 's', 'f', 'w', 'fn:', 'l:']);
if (parsed.length < 1) {
throw 'You must provide a command to run!';
}
if (parsed.options.d) {
msg.delete();
}
let ps = exec(parsed.leftover.join(' '));
if (!ps) {
throw 'Failed to start process!';
}
if (parsed.options.s) {
return;
}
let opts = {
delay: 10,
cutOn: '\n'
};
if (!parsed.options.r) {
opts.prefix = `\`\`\`${parsed.options.l || 'bash'}\n`;
opts.suffix = '\n```';
}
if (parsed.options.f) {
let output = '';
ps.stdout.on('data', data => output += data.toString());
await new Promise(resolve => {
ps.once('exit', async () => {
if (!output) {
return resolve();
}
try {
await msg.channel.send({
files: [
{
attachment: output.replace(/^file:\/\//, ''),
name: parsed.options.fn
}
]
});
} catch (err) {
msg.error('Invalid URL/path!');
}
resolve();
});
});
} else {
if (parsed.options.w) {
let output = '';
let handler = data => output += data.toString();
[ps.stdout, ps.stderr].forEach(stream => stream.on('data', handler));
await new Promise(resolve => {
ps.once('exit', async () => {
if (!output) {
return resolve();
}
await bot.utils.sendLarge(msg.channel, clean(output), opts);
resolve();
});
});
} else {
ps.stdout.on('data', data => bot.utils.sendLarge(msg.channel, clean(data), opts));
ps.stderr.on('data', data => bot.utils.sendLarge(msg.channel, clean(data), opts));
await new Promise(resolve => ps.once('exit', resolve));
}
}
};
const clean = function (data) {
return `${data}`
.replace(/`/g, '\u200b$&')
.replace(new RegExp(username, 'g'), '<Hidden>')
.replace(/\[[0-9]*m/g, '');
};
exports.info = {
name: 'exec',
usage: 'exec <command>',
description: 'Executes a command in the console',
options: [
{
name: '-s',
description: 'Runs in silent mode, not showing any console output'
},
{
name: '-l',
usage: '-l <lang>',
description: 'Sets the language of the outputted code block'
},
{
name: '-r',
description: 'Sends the output raw, without any code blocks'
},
{
name: '-d',
description: 'Deletes the command message'
},
{
name: '-f',
description: 'Interperts the response as a file URL/path to send'
},
{
name: '-fn',
usage: '-fn <name>',
description: 'Sets the name for the sent file'
},
{
name: '-w',
description: 'Wait for the program to finish before sending the output'
}
]
};

View file

@ -1,75 +0,0 @@
const got = require('got');
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'You must specify a repository or search term!';
}
const input = args.join(' ');
if (input.indexOf('/') !== -1) {
let repo = safeRepo(input);
msg.edit(`:arrows_counterclockwise: Loading info for '${repo}'...`);
const res = await got(`https://api.github.com/repos/${repo}`, { json: true });
const json = res.body;
if (json.message === 'Not Found') {
msg.error('That repository could not be found!');
}
msg.edit({
embed: bot.utils.embed('', getInfo(json))
});
} else {
msg.edit(`:arrows_counterclockwise: Searching for '${input}'...`);
const res = await got(`https://api.github.com/search/repositories?q=${args.join('+')}`, { json: true });
const json = res.body;
if (json.total_count < 1) {
throw `No results found for '${args.join(' ')}'`;
}
msg.delete();
msg.channel.send(':white_check_mark: Top 3 results:');
json.items.slice(0, 3).forEach(item => {
msg.channel.send({
embed: bot.utils.embed('', getInfo(item))
});
});
}
};
function safeRepo(input) {
if (input.indexOf('/') === -1) {
return;
}
let user = input.substr(0, input.indexOf('/'));
input = input.substr(input.indexOf('/') + 1);
let repo = input.indexOf('/') === -1 ? input : input.substr(0, input.indexOf('/'));
return `${user}/${repo}`;
}
function getInfo(json) {
return `**${json.full_name}**
\t**Description:** _${json.description || 'None provided'}_
\t**Owner:** [${json.owner.login}](${json.owner.html_url})
\t**Primary Language:** \`${json.language}\`
\t:house: [Home page](${json.html_url}) :small_red_triangle_down: [Downloads](${json.html_url}/releases) :exclamation: [Issues](${json.html_url}/issues)
\t:negative_squared_cross_mark: \`${json.open_issues_count}\` open issues :star: \`${json.stargazers_count}\` stargazers :eyes: \`${json.subscribers_count || json.watchers_count}\` watchers
\tDo \`git clone ${json.clone_url}\` to clone this repository
`;
}
exports.info = {
name: 'github',
usage: 'github <user/repo>',
description: 'Links to a GitHub repository'
};

View file

@ -1,207 +0,0 @@
const cheerio = require('cheerio');
const got = require('got');
const { stringify } = require('querystring');
const { RichEmbed } = require('discord.js');
exports.run = async (bot, msg, args) => {
if(args.length < 1) throw 'I need to know what to search...';
await msg.edit(':arrows_counterclockwise: Googling....');
const params = {
q: args.join(' '),
safe: 'on',
lr: 'lang_en',
hl: 'en'
};
let resp = await got('https://google.com/search?' + stringify(params), { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) Gecko/20100101 Firefox/53.0' }});
if(resp.statusCode !== 200) throw 'Google didn\'t want to respond somehow';
const $ = cheerio.load(resp.body);
const results = [];
let card = null;
const cardNode = $('div#rso > div._NId').find('div.vk_c, div.g.mnr-c.g-blk, div.kp-blk');
if(cardNode && cardNode.length !== 0) {
card = this.parseCards($, cardNode);
}
$('.rc > h3 > a').each((i, e) => {
const link = $(e).attr('href');
const text = $(e).text();
if(link) {
results.push({ text, link });
}
});
if(card) {
const value = results.slice(0, 3).map(r => `[${r.text}](${r.link})`).join('\n');
if(value) {
card.addField(`This is what I also found for: "${params.q}" `, value)
.setColor(bot.utils.randomColor())
.setURL(`https://google.com/search?q=${encodeURIComponent(params.q)}`);
}
return await msg.edit({ embed: card });
}
if(results.length === 0) {
return await msg.channel.send('Sorry, we didn\'t found any results');
}
const firstentry = `[${results[0].text}](${results[0].link})`;
const nexttwo = results.slice(1, 3).map(r => `[${r.text}](${r.link})`).join('\n');
const embed = bot.utils.embed(`Search results for ${args.join(' ')}`, firstentry, [
{
name: 'More links',
value: nexttwo
}
], { url: `https://google.com/search?q=${encodeURIComponent(params.q)}`});
await msg.edit('', {embed: embed});
};
exports.parseCards = ($, node) => {
const e = new RichEmbed();
//calculator card
if(node.find('span.cwclet').first().length > 0) {
e.setTitle(':nerd: Calculator');
const calculation = node.find('span.cwclet').first().text();
let result = node.find('.cwcot').first().text();
if(result)
result = `${calculation.trim()} ${result.trim()}`;
else result = `${calculation} ...`;
e.setDescription(result);
return e;
}
//unit conversion card
if(node.find('input[class*=_eif]').length > 0 && node.find('input[class*=_eif]').first().attr('value').length > 0) {
if(node.find('input[class*=_eif]').length === 2) {
e.setTitle(':scales: Unit conversion');
try {
const firstvalue = node.find('input[class*=_eif]').eq(0).attr('value');
const firstunit = node.find('input[class*=_eif]').eq(0).parent().find('select :selected').text().toLowerCase();
const secondvalue = node.find('input[class*=_eif]').eq(1).attr('value');
const secondunit = node.find('input[class*=_eif]').eq(1).parent().find('select :selected').text().toLowerCase();
e.setDescription(`${firstvalue} ${firstunit} = ${secondvalue} ${secondunit}`);
} catch(e) {
return;
}
return e;
}
}
//currency converter card
if(node.find('.ct-cs').first().length > 0) {
e.setTitle(':moneybag: Currency converter');
try {
let firsttext = node.find('.vk_sh.vk_gy.cursrc').text();
let secondtext = node.find('.vk_ans.vk_bk.curtgt > span').first().text() + node.find('.vk_ans.vk_bk.curtgt > span').eq(1).text();
let result = `${firsttext} ${secondtext}`;
e.setDescription(result);
} catch(e) {
return;
}
return e;
}
//generic info card
if(node.find('._oDd > ._Tgc').first().length > 0) {
e.setDescription(node.find('._oDd > ._Tgc').first().text());
return e;
}
//translation card
if(node.find('div#tw-ob').first().length > 0) {
const srctext = node.find('pre#tw-source-text > span').first().text();
let srclang = node.find('select#tw-sl > option:selected').first().text();
const desttext = node.find('pre#tw-target-text > span').first().text();
const destlang = node.find('select#tw-tl > option:selected').first().text();
if(srclang.includes('detected')) {
srclang = srclang.replace(' - detected', '');
}
e.setTitle(':man_with_turban: Translation card');
try {
e.addField(srclang, srctext, true);
e.addField(destlang, desttext, true);
} catch(e) {
return;
}
return e;
}
//time in card
if(node.find('div.vk_bk.vk_ans').first().length > 0) {
let time = node.find('div.vk_bk.vk_ans').text();
try {
e.setTitle(`:alarm_clock: ${node.find('span').text()}`)
.setDescription(`${time}`);
} catch(e) {
return;
}
return e;
}
//defenition cards
const words = node.find('span[data-dobid=hdw]');
if(words.length > 0) {
node.find('span[data-dobid=hdw]').each((i, word) => {
const root = node.find('span[data-dobid=hdw]').parent().parent();
const pronunciation = $(root).find('span.lr_dct_ph > span');
if(!pronunciation) return true;
const select = (selector) => $(selector).parent().parent().parent().find('ol.lr_dct_sf_sens')
.find('div.lr_dct_sf_sen.vk_txt')
.find('div._Jig > div[data-dobid=dfn] > span');
const lexicalCategory = $(root).find('div.lr_dct_sf_h > i > span');
let defenitions = select(root);
$(lexicalCategory).each((i, category) => {
defenitions = select(category);
try {
let descrip = [`${$(category).text()}`];
$(defenitions).each((i, e) => {
descrip.push(`${i + 1}. ${$(e).text()}`);
});
if(i === 0) e.addField(`${$(word).text()} / ${$(pronunciation).text()}`, descrip.join('\n'));
else e.addField(`${$(word).text()} / ${$(pronunciation).text()}`, descrip.join('\n'));
} catch(e) {
return true;
}
});
});
return e;
}
};
exports.info = {
name: 'google',
usage: 'google <search>',
description: 'Searches Google using magic'
};

View file

@ -1,34 +0,0 @@
const IMAGE_NAME = /\.(jpe?g|png|gif|webp)$/i;
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide an image URL to send.';
}
msg.delete();
const url = args[0];
let name;
if (!IMAGE_NAME.test(url)) {
name = 'image.png';
}
try {
await msg.channel.send({
file: {
name,
attachment: url
}
});
} catch (ignore) {
// Using throw inside of a catch doesn't work quite right
return msg.error('Failed to send image.');
}
};
exports.info = {
name: 'image',
usage: 'image <url>',
description: 'Sends an image from a URL'
};

View file

@ -1,38 +0,0 @@
const got = require('got');
const fs = require('fs');
const path = require('path');
exports.run = (bot, msg, args) => {
let count = parseInt(args[0]) || 100;
let attachments = [];
msg.channel.fetchMessages({ limit: Math.min(count, 100), before: msg.id }).then(messages => {
messages.map(m => {
m.attachments.map(attachment => {
if (attachment.height) {
attachments.push(attachment.url);
}
});
});
let dir = __dirname + '/../../../out';
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
for (let i = 0; i < attachments.length; i++) download(attachments[i]);
if (attachments.length === 0) throw 'Couldn\'t find any images.';
msg.channel.send(`:white_check_mark: ${attachments.length} images scraped and saved to the "out" folder in the SharpBot folder.`).then(m => { m.delete(10000); });
msg.delete();
}).catch(msg.error);
};
exports.info = {
name: 'imagedumper',
usage: 'imagedumper <amount>',
description: 'Grabs all images from the specified amount of messages (max 100)',
credits: '<@149916494183137280>' // Liam Bagge#0550
};
function download(url) {
let file = fs.createWriteStream(`${__dirname}/../../../out/attachment_${path.basename(url)}`);
got.stream(url).pipe(file);
}

View file

@ -1,26 +0,0 @@
exports.run = (bot, msg, args) => {
let parsed = bot.utils.parseArgs(args, ['i']);
if (parsed.leftover.length < 1) {
throw 'You must provide something to search for!';
}
const query = encodeURIComponent(parsed.leftover.join(' '));
// Are there better ways to do this? Sure. But why not abuse
// JavaScript's craziness, and use a truthy/falsy -> 1/0 converter?
const internetExplainer = !!parsed.options.i / 1;
msg.edit(`**Wow!** :arrow_right: http://www.lmgtfy.com/?iie=${internetExplainer}&q=${query}`);
};
exports.info = {
name: 'lmgtfy',
usage: 'lmgtfy [search text]',
description: 'Links to LMGTFY with the given search text',
options: [
{
name: '-i',
description: 'Enables Internet Explainer'
}
]
};

View file

@ -1,35 +0,0 @@
exports.run = async (bot, msg, args) => {
let parsed = bot.utils.parseArgs(args, ['o']);
if (parsed.options.o) {
return msg.edit(':stopwatch: Ping').then(m => {
let time = msg.editedTimestamp - msg.createdTimestamp;
bot.utils.playAnimation(m, 500, [
':stopwatch: __P__ing',
':stopwatch: __Pi__ng',
':stopwatch: __Pin__g',
':stopwatch: __Ping__',
`:stopwatch: ***Pong!*** \`${time}ms\``
]);
});
}
await msg.edit(':thinking: Ping');
const delay = msg.editedTimestamp - msg.createdTimestamp;
(await msg.edit(`:stopwatch: Pong! \`${delay}ms\``)).delete(5000);
};
exports.info = {
name: 'ping',
usage: 'ping [-o]',
description: 'Pings the bot',
options: [
{
name: '-o',
usage: '-o',
description: 'Shows the old ping message (animated)'
}
]
};

View file

@ -1,148 +0,0 @@
const discordEmoji = require('discord-emoji');
const emoji = {};
Object.values(discordEmoji).forEach(value => {
Object.keys(value).forEach(key => {
emoji[key] = value[key];
});
});
const mappings = {
'a': [':regional_indicator_a:', ':a:'],
'b': [':regional_indicator_b:', ':b:'],
'c': [':regional_indicator_c:'],
'd': [':regional_indicator_d:'],
'e': [':regional_indicator_e:'],
'f': [':regional_indicator_f:'],
'g': [':regional_indicator_g:', ':compression:'],
'h': [':regional_indicator_h:'],
'i': [':regional_indicator_i:', ':information_source:'],
'j': [':regional_indicator_j:'],
'k': [':regional_indicator_k:'],
'l': [':regional_indicator_l:'],
'm': [':regional_indicator_m:', ':m:'],
'n': [':regional_indicator_n:'],
'o': [':regional_indicator_o:', ':o2:', ':o:'],
'p': [':regional_indicator_p:', ':parking:'],
'q': [':regional_indicator_q:'],
'r': [':regional_indicator_r:'],
's': [':regional_indicator_s:'],
't': [':regional_indicator_t:', ':cross:'],
'u': [':regional_indicator_u:'],
'v': [':regional_indicator_v:'],
'w': [':regional_indicator_w:'],
'x': [':regional_indicator_x:', ':heavy_multiplication_x:', ':x:', ':negative_squared_cross_mark:'],
'y': [':regional_indicator_y:'],
'z': [':regional_indicator_z:'],
'0': [':zero:'],
'1': [':one:'],
'2': [':two:'],
'3': [':three:'],
'4': [':four:'],
'5': [':five:'],
'6': [':six:'],
'7': [':seven:'],
'8': [':eight:'],
'9': [':nine:'],
'!': [':exclamation:', ':grey_exclamation:'],
'?': [':question:', ':grey_question:'],
'*': [':asterisk:', ':eight_spoked_asterisk:'],
'#': [':hash:'],
'$': [':heavy_dollar_sign:']
};
function clone(object) {
const newObject = {};
Object.keys(object).forEach(key => {
if (object[key] instanceof Array) {
newObject[key] = new Array(...object[key]);
} else {
newObject[key] = object[key];
}
});
return newObject;
}
function emojiToUnicode(input) {
if (/^:regional_indicator_[a-z]:$/.test(input)) {
return String.fromCharCode(55356) + String.fromCharCode(56806 + input.substr(20, 1).charCodeAt(0) - 97);
}
return emoji[input.slice(1, -1)];
}
function react(message, remaining, allowedMappings) {
if (remaining.length < 1) {
// We're out of stuff
return;
}
const char = remaining.shift().toLowerCase();
if (!char) {
return;
}
if (!allowedMappings[char]) {
// Not a usable char
return;
}
const next = allowedMappings[char].shift();
if (!next) {
// We have no more mappings available
return;
}
message.react(emojiToUnicode(next)).then(() => {
react(message, remaining, allowedMappings);
});
}
exports.run = (bot, msg, args) => {
if (args.length < 1) {
throw 'You must provide some text to react with.';
}
const fetchOptions = { limit: 1 };
if (args[1]) {
if (!/\d{18}/.test(args[1])) {
throw `${args[1]} is not a valid message ID!`;
}
fetchOptions.around = args[1];
} else {
fetchOptions.before = msg.id;
}
msg.channel.fetchMessages(fetchOptions).then(messages => {
if (messages.length < 1) {
return msg.error('Failed to find the message.');
}
const target = messages.first();
const allowedMappings = clone(mappings);
// Remove current reactions from allowed emojis
target.reactions.forEach(reaction => {
const emoji = reaction.toString();
for (const key in allowedMappings) {
const index = allowedMappings[key].indexOf(emoji);
if (index > -1) {
allowedMappings[key].splice(index, 1);
}
}
});
msg.delete();
react(target, args[0].split(''), allowedMappings);
}).catch(msg.error);
};
exports.info = {
name: 'react',
usage: 'react <text> [message ID]',
description: 'Reacts to the last sent message (or another message) with a given text (cannot contain spaces)'
};

View file

@ -1,10 +0,0 @@
exports.run = async (bot, msg) => {
await msg.edit(':wave: Restarting. Bye!');
bot.shutdown(true);
};
exports.info = {
name: 'restart',
usage: 'restart',
description: 'Restarts the bot'
};

View file

@ -1,37 +0,0 @@
exports.run = (bot, msg, args) => {
const parsed = bot.utils.parseArgs(args, ['c:']);
if (parsed.leftover.length < 1) {
throw 'You must put something to say!';
}
let channel = msg.channel;
if (parsed.options.c) {
const id = parsed.options.c.match(/\d{18}/)[0];
if (!id) {
throw 'Invalid channel!';
}
channel = bot.channels.get(id);
if (!channel) {
throw 'That channel could not be found!';
}
}
msg.delete();
channel.send(parsed.leftover.join(' '));
};
exports.info = {
name: 'say',
usage: 'say <message>',
description: 'Says the message you put. Useful for shortcuts.',
options: [
{
name: '-c',
usage: '-c <channel|channel ID>',
description: 'Specifies a specific channel to send the message in'
}
]
};

View file

@ -1,94 +0,0 @@
exports.init = bot => {
this.storage = bot.storage('shortcuts');
};
const ADD = /^a(dd)?|c(reate)?$/i;
const EDIT = /^e(dit)?$/i;
const DELETE = /^d(el(ete)?)?|r(em(ove)?)?$/i;
const INFO = /^i(nfo)?$/i;
exports.run = (bot, msg, args) => {
if (args.length < 1) {
const shortcuts = this.storage.values;
if (shortcuts.length < 1) {
throw 'You have no shortcuts!';
}
const list = shortcuts.map(shortcut => `- \`${shortcut.name}\``).join('\n');
msg.delete();
return bot.utils.sendLarge(msg.channel, `**Shortcuts:**\n${list}`, { cutOn: '\n' });
}
if (ADD.test(args[0]) || EDIT.test(args[0])) {
if (args.length < 3) {
throw `Usage: \`${bot.config.prefix}shortcut add|edit <id> <command>\``;
}
let id = args[1].toLowerCase();
let command = args.slice(2).join(' ');
// People keep accidentally putting their command prefix in
if (command.startsWith(bot.config.prefix)) {
command = command.substr(bot.config.prefix.length);
}
const shortcut = this.storage.get(id);
if (shortcut && !EDIT.test(args[0])) {
throw `The shortcut \`${id}\` already exists!`;
}
this.storage.set(id, { name: id, command });
this.storage.save();
msg.edit(`:white_check_mark: Created shortcut \`${id}\`.`)
.then(m => m.delete(5000));
} else if (DELETE.test(args[0])) {
if (args.length < 2) {
throw `Usage: \`${bot.config.prefix}shortcut delete <id>\``;
}
let id = args[1];
const shortcut = this.storage.get(id);
if (!shortcut) {
throw `The shortcut \`${id}\` doesn't exist!`;
}
this.storage.set(id);
this.storage.save();
msg.edit(`:white_check_mark: Removed the shortcut \`${id}\`.`)
.then(m => m.delete(5000));
} else if (INFO.test(args[0])) {
if (args.length < 2) {
throw `Usage: \`${bot.config.prefix}shortcut info <name>\``;
}
const id = args[1];
const shortcut = this.storage.get(id);
if (!shortcut) {
throw `The shortcut \`${id}\` doesn't exist!`;
}
msg.edit(`**Name:** \`${shortcut.name}\`\n\`\`\`xl\n${shortcut.command}\n\`\`\``)
.then(m => m.delete(30000));
} else {
bot.commands.get('help').run(bot, msg, ['shortcuts']);
}
};
exports.info = {
name: 'shortcuts',
usage: 'shortcuts [add <name> <command>|edit <name> <command>|delete <name>|info <name>]',
description: 'Controls or lists your shortcuts',
examples: [
'shortcuts add love embed -c #ff0000 <3',
'shortcuts edit drpg say #!mine;; say #!forage;; say #!chop;; say #!fish',
'shortcuts delete invite',
'shortcuts info love',
'shortcuts'
]
};

View file

@ -1,34 +0,0 @@
const got = require('got');
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide a url to shorten!';
}
const url = args.join(' ');
msg.delete();
const res = await got(`http://tinyurl.com/api-create.php?url=${encodeURIComponent(url)}`);
msg.channel.send({
embed: bot.utils.embed('', '', [
{
name: 'Link',
value: url
},
{
name: 'Short URL',
value: res.body
}
])
});
};
exports.info = {
name: 'shorturl',
aliases: ['short'],
usage: 'shorturl <url>',
description: 'Shortens a URL',
credits: 'xd <@335490180028956673>'
};

View file

@ -1,10 +0,0 @@
exports.run = async (bot, msg) => {
await msg.edit(':wave: Shutting down. Bye!');
bot.shutdown(false);
};
exports.info = {
name: 'shutdown',
usage: 'shutdown',
description: 'Fully shuts the bot down'
};

View file

@ -1,135 +0,0 @@
const RichEmbed = require('discord.js').RichEmbed;
const SpotifyWebApi = require('spotify-web-api-node');
const SpotifyUriParser = require('spotify-uri');
const got = require('got');
const spotifyApi = new SpotifyWebApi();
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'You must specify a Spotify URI at least!';
}
const response = await got('https://spotify-auth.doxylamin.pw/', { json: true });
if (response.body.success == true) {
spotifyApi.setAccessToken(response.body.access_token);
}
const parsed = bot.utils.parseArgs(args, ['preview']);
const spotifyUri = SpotifyUriParser.parse(parsed.leftover.join(' '));
switch (spotifyUri.type) {
case 'track':
getTrackEmbed(msg, spotifyUri.id, parsed.options.preview);
break;
case 'artist':
getArtistEmbed(msg, spotifyUri.id, parsed.options.preview);
break;
case 'playlist':
getPlaylistEmbed(msg, spotifyUri.user, spotifyUri.id, parsed.options.preview);
break;
default:
throw 'Sorry, I can\'t parse that type of URI yet.';
}
};
function getPlaylistEmbed(msg, user, spotifyId, withPreview) {
spotifyApi.getPlaylist(user, spotifyId)
.then(data => {
const apiResponse = data.body;
const embed = new RichEmbed()
.setColor([30, 215, 96])
.setThumbnail(apiResponse.images[0].url)
.setAuthor('Click to listen on Spotify', 'https://image.flaticon.com/icons/png/512/174/174872.png', apiResponse.external_urls.spotify)
.addField('Playlist Name', apiResponse.name, true)
.addField('Created by', apiResponse.owner.display_name, true)
.addField('Description', apiResponse.description, true)
.addField('Public Playlist', ((apiResponse.public) ? 'Yes' : 'No'), true)
.addField('Collaborative', ((apiResponse.collaborative) ? 'Yes' : 'No'), true)
.addField('Followers', apiResponse.followers.total, true)
.addField('Track Count', apiResponse.tracks.total, true);
msg.edit({ embed });
if (withPreview) msg.channel.send(`Got spotify? Click below to play! ${apiResponse.external_urls.spotify}`);
}).catch(err => {
throw `Something went wrong! ${err}`;
});
}
function getArtistEmbed(msg, spotifyId, withPreview) {
spotifyApi.getArtist(spotifyId)
.then(data => {
const apiResponse = data.body;
const embed = new RichEmbed()
.setColor([30, 215, 96])
.setThumbnail(apiResponse.images[0].url)
.setAuthor('Click to listen on Spotify', 'https://image.flaticon.com/icons/png/512/174/174872.png', apiResponse.external_urls.spotify)
.addField('Artist Name', apiResponse.name, true)
.addField('Followers', apiResponse.followers.total.toLocaleString(), true)
.addField('Popularity', apiResponse.popularity + '%', true)
.addField('Genres', ((apiResponse.genres.length > 0) ? apiResponse.genres.join(', ') : 'unknown'), true);
msg.edit({ embed });
if (withPreview) msg.channel.send(`Got spotify? Click below to play! ${apiResponse.external_urls.spotify}`);
}).catch(err => {
throw `Something went wrong! ${err}`;
});
}
function getTrackEmbed(msg, spotifyId, withPreview) {
spotifyApi.getTrack(spotifyId)
.then(data => {
const apiResponse = data.body;
let artists = apiResponse.artists.map(artist => artist.name);
const embed = new RichEmbed()
.setColor([30, 215, 96])
.setThumbnail(apiResponse.album.images[0].url)
.setAuthor('Click to listen on Spotify', 'https://image.flaticon.com/icons/png/512/174/174872.png', apiResponse.external_urls.spotify)
.addField('Artist', artists.join(', '), true)
.addField('Title', apiResponse.name, true)
.addField('Length', calculateDuration(apiResponse.duration_ms), true)
.addField('Album', apiResponse.album.name, true)
.addField('Parental Advisory', ((apiResponse.explicit) ? 'contains explicit lyrics' : 'none applicable'), true)
.addField('Availability', `Available in ${apiResponse.available_markets.length} countrys`, true)
.addField('Popularity', `${apiResponse.popularity}%`, true);
msg.edit({ embed });
if (withPreview) msg.channel.send(`Got spotify? Click below to play! ${apiResponse.external_urls.spotify}`);
}).catch(err => {
throw `Something went wrong! ${err}`;
});
}
function calculateDuration(ms) {
const minutes = Math.floor(ms / 60000);
const seconds = ((ms % 60000) / 1000).toFixed(0);
return (seconds == 60 ? (minutes + 1) + ':00' : minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
}
exports.info = {
name: 'spotify',
usage: 'spotify <url>',
description: 'Parses a spotify-uri and outputs its information.',
examples: [
'spotify spotify:track:5DkCAVqn09WAPOPiphKOUD',
'spotify -preview spotify:track:5DkCAVqn09WAPOPiphKOUD',
'spotify https://open.spotify.com/track/5DkCAVqn09WAPOPiphKOUD'
],
options: [
{
name: '-preview',
description: 'Sends another message where discord places it\'s own embedded player'
}
],
credits: '<@140541588915879936>' // Doxylamin#3377
};

View file

@ -1,43 +0,0 @@
const validStatuses = [
{
internal: 'online',
display: 'online',
emoji: ':zap:'
},
{
internal: 'idle',
display: 'idle',
emoji: ':beach_umbrella:'
},
{
internal: 'dnd',
display: 'do-not-disturb',
emoji: ':mute:'
},
{
internal: 'invisible',
display: 'invisible',
emoji: ':ghost:'
}
];
const validStatusRegex = new RegExp(`^(${validStatuses.map(status => status.internal).join('|')})$`);
const validStatusString = validStatuses.map(status => `\`${status.internal}\``).join(', ');
exports.run = async (bot, msg, args) => {
if (args.length < 1 || !validStatusRegex.test(args[0])) {
throw `Please provide a status to set: ${validStatusString}`;
}
const status = validStatuses.find(status => status.internal === args[0].toLowerCase());
bot.user.setStatus(status.internal);
(await msg.edit(`${status.emoji} Set status to ${status.display}.`)).delete(5000);
};
exports.info = {
name: 'status',
usage: `status <${validStatuses.map(status => status.internal).join('|')}>`,
description: 'Sets your status'
};

View file

@ -1,70 +0,0 @@
exports.init = bot => {
this.storage = bot.storage('tags');
};
exports.run = async (bot, message, args) => {
if (args.length < 1) {
throw `Do \`${bot.config.prefix}help tag\` for info on how to use this command.`;
}
const sub = args[0].toLowerCase();
args = args.slice(1);
if (sub === 'list') {
const tags = this.storage.values
.sort((a, b) => b.used - a.used);
message.edit(`${tags.map(tag => `**${tag.name}** (${tag.used})`).join('\n')}`, { split: true });
} else if (sub === 'add') {
if (args.length < 2) {
throw 'You must provide a tag name and the tag contents!';
}
let name = args[0];
let contents = args.slice(1).join(' ');
const tag = this.storage.get(name);
if (tag) {
throw 'That tag already exists!';
}
this.storage.set(name, { name, contents, used: 0 });
this.storage.save();
(await message.edit(`:white_check_mark: The tag \`${name}\` was added.`)).delete(5000);
} else if (sub === 'delete') {
if (args.length < 1) {
throw 'You must provide a tag name to delete!';
}
const name = args[0];
if (!this.storage.get(name)) {
throw 'That tag does not exist!';
}
this.storage.set(name);
this.storage.save();
(await message.edit(`:white_check_mark: The tag \`${name}\` was deleted.`)).delete(5000);
} else {
const tag = this.storage.get(sub);
if (!tag) {
throw 'That tag does not exist!';
}
message.edit(args.join(' ') + tag.contents);
tag.used++;
this.storage.set(sub, tag);
this.storage.save();
}
};
exports.info = {
name: 'tag',
usage: 'tag <name>|list|add <name> <content>|delete <name>',
description: 'Manages your tags'
};

View file

@ -1,40 +0,0 @@
function makeCommand(name, displayName, methodName) {
return {
run: async (bot, msg, args) => {
const parsed = bot.utils.parseArgs(args, 'r');
if (parsed.leftover.length < 1) {
throw 'You must have something to upload!';
}
await msg.edit(':arrows_counterclockwise: Uploading...');
const { url, rawUrl } = await bot.utils[methodName](parsed.leftover.join(' '));
if (!url) {
throw 'Failed to upload, no key was returned!';
}
if (parsed.options.r) {
msg.edit(`:white_check_mark: ${rawUrl}`);
} else {
msg.edit(`:white_check_mark: ${url}`);
}
},
info: {
name,
usage: `${name} <text>`,
description: `Uploads some text to ${displayName}`,
options: [
{
name: '-r',
description: 'Returns the URL for a raw version of your upload'
}
]
}
};
}
module.exports = [
makeCommand('haste', 'Hastebin', 'hastebinUpload'),
makeCommand('ix', 'ix.io', 'ixUpload')
];

View file

@ -1,54 +0,0 @@
const got = require('got');
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'You must specify a time to convert';
}
let input = args.join(' ');
let url = `https://api.duckduckgo.com/?q=${encodeURIComponent(input)}&format=json`;
await msg.edit(':arrows_counterclockwise: Loading conversion...');
const res = await got(url, { json: true });
if (!res || !res.body) {
throw 'Could not load data from DDG.';
}
let data = res.body;
let answer = data['Answer'];
let message;
if (data['AnswerType'] === 'timezone_converter') {
msg.delete();
let matches = input.match(/(.*?)\s*(to|in)\s*(.*)/);
let prefix;
if (matches) {
prefix = matches[1];
} else {
prefix = input;
}
message = bot.utils.embed('', '', [
{
name: 'Timezone:',
value: `${prefix} \u2794 ${answer}`
}
]);
msg.channel.send({ embed: message });
} else {
throw `No conversion found for ${input}`;
}
};
exports.info = {
name: 'timezone',
usage: 'timezone <time> to <time>',
description: 'converts between timezones, using DuckDuckGo searches',
credits: '<@136641861073764352>' // Abyss#0473
};

View file

@ -1,254 +0,0 @@
const {stripIndents} = require('common-tags');
class TodoItem {
constructor(description, completed = false) {
this.description = description;
this.completed = completed;
}
complete(completed = true) {
this.completed = completed;
}
toString() {
return `${this.completed ? ':ballot_box_with_check:' : ':black_square_button: '} ${this.description}`;
}
static fromJSON({description, completed}) {
return new TodoItem(description, completed);
}
}
class TodoList {
constructor(name) {
this.name = name;
this.items = [];
}
_validateIndex(index) {
if (Number.isNaN(index)) {
// This will throw the error below
index = 0;
}
index -= 1;
if (index < 0 || index > this.items.length) {
throw 'Please specify a valid number!';
}
return index;
}
add(description, completed = false) {
this.items.push(new TodoItem(description, completed));
}
remove(index) {
index = this._validateIndex(index);
this.items.splice(index, 1);
}
markComplete(index, completed = true) {
index = this._validateIndex(index);
this.items[index].complete(completed);
}
toString() {
return stripIndents`
**List: ${this.name}**
**Items:** ${this.items.length === 0 ? 'None' : ''}
${this.items.map((item, i) => `${i + 1}. ${item.toString()}`).join('\n')}
`;
}
static fromJSON({name, items}) {
const todoList = new TodoList(name);
todoList.items = items.map(item => TodoItem.fromJSON(item));
return todoList;
}
}
class TodoLists {
constructor(bot) {
this._bot = bot;
this.storage = bot.storage('todos');
this.lists = {};
const lists = this.storage.get(TodoLists.listsStorageKey);
if (!lists) {
this.lists = {
[TodoLists.mainListName]: new TodoList(TodoLists.mainListName)
};
} else {
Object.keys(lists)
.forEach(listName => {
this.lists[listName] = TodoList.fromJSON(lists[listName]);
});
}
let currentList = this.storage.get(TodoLists.currentListStorageKey);
if (!this.getList(currentList)) {
currentList = TodoLists.mainListName;
}
this.currentListName = currentList;
}
/**
*
* @returns {TodoList}
*/
getCurrentList() {
return this.getList(this.currentListName);
}
save() {
this.storage.set(TodoLists.currentListStorageKey, this.currentListName);
this.storage.set(TodoLists.listsStorageKey, this.lists);
this.storage.save();
}
getList(name) {
return this.lists[name];
}
getListNames() {
return Object.keys(this.lists);
}
deleteList(name) {
if (!this.getList(name)) {
throw `List '${name}' does not exist!`;
}
if (name === TodoLists.mainListName) {
throw `List '${name}' cannot be deleted!`;
}
delete this.lists[name];
if (this.currentListName === name) {
this.switchList(TodoLists.mainListName);
}
}
createList(name) {
if (this.getList(name)) {
throw `List'${name}' already exists!`;
}
this.lists[name] = new TodoList(name);
this.switchList(name);
}
switchList(name) {
if (!this.getList(name)) {
throw `List '${name}' does not exist!`;
}
this.currentListName = name;
}
}
TodoLists.listsStorageKey = 'lists';
TodoLists.currentListStorageKey = 'currentListName';
TodoLists.mainListName = 'Main';
module.exports.run = (bot, msg, args) => {
const send = (message, deleteInSeconds = 5, prefix = ':white_check_mark: ') => msg.edit({
embed: bot.utils.embed(`Todo List Utility (message will self-destruct in ${deleteInSeconds} seconds)`, `${prefix}${message}`)
})
.then(m => m.delete(deleteInSeconds * 1000));
if (args.length < 1) {
return send(Lists.getCurrentList(), 45, '');
}
const {options, leftover} = bot.utils.parseArgs(args, ['d', 'c', 'i', 'l', 'n', 'r', 's']);
let indexOption = parseInt(leftover[0], 10);
const ensureProperNumberOfArgs = (max, message = 'Expected list item number only', min = 1) => {
if (leftover.length > max || leftover.length < min) {
throw message;
}
};
if (options.c) {
ensureProperNumberOfArgs(1);
Lists.getCurrentList().markComplete(indexOption);
send(`Item ${indexOption} marked complete!`);
} else if (options.i) {
ensureProperNumberOfArgs(1);
Lists.getCurrentList().markComplete(indexOption, false);
send(`Item ${indexOption} marked incomplete!`);
} else if (options.d) {
ensureProperNumberOfArgs(1);
Lists.getCurrentList().remove(indexOption);
send(`Item ${indexOption} deleted!`);
} else if (options.l) {
send(`Available lists: ${Lists.getListNames().join(', ')}`, 30);
} else if (options.n) {
ensureProperNumberOfArgs(1, 'Expected name of new list to be a single word');
Lists.createList(leftover[0]);
send(`List '${leftover[0]}' created!`);
} else if (options.r) {
ensureProperNumberOfArgs(1, 'Expected name of list to delete to be a single word');
Lists.deleteList(leftover[0]);
send(`List '${leftover[0]}' deleted!`);
} else if (options.s) {
ensureProperNumberOfArgs(1, 'Expected name of chosen list to be a single word');
Lists.switchList(leftover[0]);
send(`Switched to list '${leftover[0]}'`);
} else {
Lists.getCurrentList().add(leftover.join(' '));
send(`Item '${leftover.join(' ')}' added!`);
}
Lists.save();
};
/**
* @type {TodoLists}
*/
let Lists;
module.exports.init = bot => {
Lists = new TodoLists(bot);
};
module.exports.info = {
name: 'todo',
usage: 'todo | todo [options...] <index> | todo <text of item to add>',
description: 'Manage a todo list. The command by itself will show the items in the current list.',
options: [
{
name: '-c',
usage: '-c ',
description: 'Mark an item complete'
},
{
name: '-i',
usage: '-i ',
description: 'Mark an item incomplete'
},
{
name: '-d',
usage: '-d',
description: 'Delete an item'
},
{
name: '-l',
usage: '-l',
description: 'Show all lists'
},
{
name: '-n',
usage: '-n ',
description: 'Make a new list and set it as the current list'
},
{
name: '-r',
usage: '-r ',
description: 'Remove a list. If the list being removed is the list currently in use, automatically switches back to the Main list.'
},
{
name: '-s',
usage: '-s ',
description: 'Switch lists'
}
]
};

View file

@ -1,55 +0,0 @@
const translate = require('google-translate-api');
const stripIndents = require('common-tags').stripIndents;
exports.run = async (bot, msg, args) => {
let parsed = bot.utils.parseArgs(args, ['e', 'f:']);
if (parsed.leftover.length < 2) {
throw 'You must provide a language and some text to translate!';
}
let lang = parsed.leftover[0];
let input = parsed.leftover.slice(1).join(' ');
await msg.edit(':arrows_counterclockwise: **Translating your Text...**');
let res;
try {
res = await translate(input, { from: parsed.options.f, to: lang });
} catch (e) {
return msg.error(`Failed to translate: ${e.message}`);
}
if (parsed.options.e) {
return msg.edit(res.text);
}
msg.delete();
msg.channel.send({
embed: bot.utils.embed('', stripIndents`
**From:** __\`${parsed.options.f || '[auto]'}\`__
**To:** __\`${lang}\`__
**Input:**\n\`\`\`\n${input}\n\`\`\`
**Output:**\n\`\`\`\n${res.text}\n\`\`\`
`)
});
};
exports.info = {
name: 'translate',
usage: 'translate <lang> <text>',
description: 'Translates text from/to any language',
credits: 'Carbowix',
options: [
{
name: '-e',
description: 'Edits your message with the translation instead of showing an embed'
},
{
name: '-f',
usage: '-f <language>',
description: 'Sets the `from` language, this is `auto` by default'
}
]
};

View file

@ -1,70 +0,0 @@
const got = require('got');
const countries = require('country-data').countries.all;
const makeURL = (city) => `https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22${encodeURIComponent(city)}%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys`;
const celsius = (fahrenheit) => Math.round(((fahrenheit - 32) * 5) / 9);
const spacer = {
name: '\u200b',
value: '\u200b',
};
exports.run = async (bot, msg, args) => {
if (args.length < 1) {
throw 'Please provide a city.';
}
const city = args.join(' ');
const res = await got(makeURL(city), { json: true });
if (!res || !res.body || !res.body.query || !res.body.query.results || !res.body.query.results.channel) {
throw 'Failed to load weather info!';
}
const weatherInfo = res.body.query.results.channel;
const forecast = weatherInfo.item.forecast[0];
const countryInfo = countries.find(country => country.name === weatherInfo.location.country);
const countryEmoji = countryInfo ? countryInfo.emoji : ':grey_question:';
const description = `The current temperature in ${weatherInfo.location.city} is ${weatherInfo.item.condition.temp}°F/${celsius(weatherInfo.item.condition.temp)}°C`;
const embed = bot.utils.embed(`${countryEmoji} ${weatherInfo.item.title}`, description, [
{
name: 'Condition',
value: weatherInfo.item.condition.text
},
{
name: 'Humidity',
value: weatherInfo.atmosphere.humidity + '%'
},
{
name: ':wind_blowing_face: Wind',
value: `*${weatherInfo.wind.speed}mph* ; direction: *${weatherInfo.wind.direction}°*`
},
{
name: `Forecast for today is *${forecast.text}*`,
value: `Highest temp is ${forecast.high}°F/${celsius(forecast.high)}°C, lowest temp is ${forecast.low}°F/${celsius(forecast.low)}°C`,
},
spacer,
spacer,
spacer,
spacer,
{
name: ':sunrise: Sunrise',
value: weatherInfo.astronomy.sunrise
},
{
name: ':city_sunset: Sunset',
value: weatherInfo.astronomy.sunset
}
], { inline: true });
msg.edit({ embed });
};
exports.info = {
name: 'weather',
usage: 'weather <city>',
description: 'Shows weather info for city'
};

View file

@ -1,10 +0,0 @@
exports.run = function (bot, msg, args) {
// insert code here
msg.channel.send(`You typed: ${args.join(' ')}`);
};
exports.info = {
name: '',
usage: '',
description: ''
};