Remove nsfw/useless commands, refactor stuff

This commit is contained in:
Dragon Fire
2018-08-15 19:34:34 -04:00
parent cc3680009a
commit b3c6b591d3
38 changed files with 192 additions and 531 deletions
+6 -15
View File
@@ -8,22 +8,22 @@
Xiao is a Discord bot coded in JavaScript with
[discord.js](https://discord.js.org/) using the
[Commando](https://github.com/discordjs/Commando) command framework. With
[Commando](https://github.com/discordjs/Commando) command framework. With nearly
300 commands, she is one of the most feature-filled bots out there.
## Invite
The bot is no longer available for invite. You can self-host the bot, or use her
on the [home server](https://discord.gg/sbMe32W).
## Commands (300)
## Commands (291)
### Utility:
* **eval**: Executes JavaScript code.
* **changelog**: Responds with Xiao's latest 10 commits.
* **donate**: Responds with Xiao's donation links.
* **changelog**: Responds with the bot's latest 10 commits.
* **donate**: Responds with the bot's donation links.
* **help**: Displays a list of available commands, or detailed information for a specific command.
* **info**: Responds with detailed bot information.
* **invite**: Responds with Xiao's invite links.
* **invite**: Responds with the bot's invite links.
* **ping**: Checks the bot's ping to the Discord server.
### Discord Information:
@@ -63,7 +63,6 @@ on the [home server](https://discord.gg/sbMe32W).
* **kiss-marry-kill**: Determines who to kiss, who to marry, and who to kill.
* **magic-conch**: Asks your question to the Magic Conch.
* **name**: Responds with a random name, with the gender of your choice.
* **new-york-times**: Searches the New York Times for your query.
* **number-fact**: Responds with a random fact about a specific number.
* **offspring**: Determines if your new child will be a boy or a girl.
* **opinion**: Determines the opinion on something.
@@ -94,7 +93,6 @@ on the [home server](https://discord.gg/sbMe32W).
* **its-joke**: It's joke!
* **just-do-it**: Sends a link to the "Just Do It!" motivational speech.
* **lenny**: Responds with the lenny face.
* **nitro**: Sends the "This message can only be viewed by users with Discord Nitro." message.
* **slow-clap**: _slow clap_
* **spam**: Responds with a picture of Spam.
* **tableflip**: Flips a table... With animation!
@@ -116,16 +114,13 @@ on the [home server](https://discord.gg/sbMe32W).
### Search:
* **bulbapedia**: Searches Bulbapedia for your query.
* **danbooru**: Responds with an image from Danbooru, with optional query.
* **derpibooru**: Responds with an image from Derpibooru.
* **deviantart**: Responds with an image from a DeviantArt section, with optional query.
* **dictionary**: Defines a word.
* **discord-js-docs**: Searches the Discord.js docs for your query.
* **eshop**: Searches the Nintendo eShop for your query.
* **esrb**: Searches ESRB for your query.
* **flickr**: Searches Flickr for your query.
* **forecast**: Responds with the seven-day forecast for a specific location.
* **gelbooru**: Responds with an image from Gelbooru, with optional query.
* **giphy**: Searches Giphy for your query.
* **github**: Responds with information on a GitHub repository.
* **google-autofill**: Responds with a list of the Google Autofill results for a particular query.
@@ -138,7 +133,6 @@ on the [home server](https://discord.gg/sbMe32W).
* **itunes**: Searches iTunes for your query.
* **jisho**: Defines a word, but with Japanese.
* **kickstarter**: Searches Kickstarter for your query.
* **konachan**: Responds with an image from Konachan, with optional query.
* **league-of-legends-champion**: Responds with information on a League of Legends champion.
* **map**: Responds with a map of a specific location.
* **mdn**: Searches MDN for your query.
@@ -154,9 +148,7 @@ on the [home server](https://discord.gg/sbMe32W).
* **recipe**: Searches for recipes based on your query.
* **rotten-tomatoes**: Searches Rotten Tomatoes for your query.
* **rule-of-the-internet**: Responds with a rule of the internet.
* **rule34**: Responds with an image from Rule34, with optional query.
* **safebooru**: Responds with an image from Safebooru, with optional query.
* **scrabble-score**: Responds with the scrabble score of a word.
* **stack-overflow**: Searches Stack Overflow for your query.
* **steam**: Searches Steam for your query.
* **stocks**: Responds with the current stocks for a specific symbol.
@@ -323,7 +315,6 @@ on the [home server](https://discord.gg/sbMe32W).
* **webhook**: Posts a message to the webhook defined in your `process.env`.
* **yoda**: Converts text to Yoda speak.
* **zalgo**: Converts text to zalgo.
* **🅱**: Replaces b with 🅱.
### Number Manipulation:
@@ -331,11 +322,11 @@ on the [home server](https://discord.gg/sbMe32W).
* **final-grade-calculator**: Determines the grade you need to make on your final to get your desired course grade.
* **math**: Evaluates a math expression.
* **roman-numeral**: Converts a number to roman numerals.
* **scrabble-score**: Responds with the scrabble score of a word.
* **units**: Converts units to/from other units.
### Other:
* **cleverbot**: Chat with Cleverbot.
* **prune**: Deletes up to 99 messages from the current channel.
* **strawpoll**: Generates a Strawpoll with the options you provide.
+1
View File
@@ -9,6 +9,7 @@ module.exports = class DickCommand extends Command {
group: 'analyze',
memberName: 'dick',
description: 'Determines your dick size.',
nsfw: true,
args: [
{
key: 'user',
+9 -19
View File
@@ -11,31 +11,21 @@ module.exports = class GenderAnalyzeCommand extends Command {
description: 'Determines the gender of a name.',
args: [
{
key: 'first',
label: 'first name',
prompt: 'What first name do you want to determine the gender of?',
type: 'string',
max: 500,
parse: first => encodeURIComponent(first)
},
{
key: 'last',
label: 'last name',
prompt: 'What last name do you want to determine the gender of?',
type: 'string',
default: 'null',
max: 500,
parse: last => encodeURIComponent(last)
key: 'name',
prompt: 'What name do you want to determine the gender of?',
type: 'string'
}
]
});
}
async run(msg, { first, last }) {
async run(msg, { name }) {
try {
const { body } = await request.get(`https://api.namsor.com/onomastics/api/json/gender/${first}/${last}`);
if (body.gender === 'unknown') return msg.say(`I have no idea what gender ${body.firstName} is.`);
return msg.say(`I'm ${Math.abs(body.scale * 100)}% sure ${body.firstName} is a ${body.gender} name.`);
const { body } = await request
.get(`https://api.genderize.io/`)
.query({ name });
if (!body.gender) return msg.say(`I have no idea what gender ${body.name} is.`);
return msg.say(`I'm ${body.probability * 100}% sure ${body.name} is a ${body.gender} name.`);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
+1 -6
View File
@@ -1,6 +1,5 @@
const Command = require('../../structures/Command');
const Random = require('random-js');
const { stripIndents } = require('common-tags');
module.exports = class ShipCommand extends Command {
constructor(client) {
@@ -30,10 +29,6 @@ module.exports = class ShipCommand extends Command {
if (first.id === second.id) return msg.reply('Shipping someone with themselves would be pretty weird.');
const random = new Random(Random.engines.mt19937().seed(Math.abs(first.id - second.id)));
const level = random.integer(0, 100);
const repeat = Math.floor(level / 5);
return msg.say(stripIndents`
${first.username} and ${second.username} have a compatability of... **${level}%**!
💟 \`[${'■'.repeat(repeat)}${' '.repeat(20 - repeat)}]\` 💟
`);
return msg.say(`${first.username} and ${second.username} have a compatability of... **${level}%**!`);
}
};
+1 -1
View File
@@ -21,6 +21,6 @@ module.exports = class EmojiImageCommand extends Command {
}
run(msg, { emoji }) {
return msg.say({ files: [emoji.url] });
return msg.say(emoji.url);
}
};
+34
View File
@@ -0,0 +1,34 @@
const Command = require('../../structures/Command');
const { MessageEmbed } = require('discord.js');
module.exports = class MessageInfoCommand extends Command {
constructor(client) {
super(client, {
name: 'message-info',
aliases: ['message', 'msg', 'msg-info', 'reply'],
group: 'info',
memberName: 'message',
description: 'Responds with detailed information on a message.',
clientPermissions: ['EMBED_LINKS'],
args: [
{
key: 'message',
prompt: 'Which message would you like to get information on?',
type: 'message'
}
]
});
}
run(msg, { message }) {
const embed = new MessageEmbed()
.setColor(message.member ? message.member.displayHexColor : 0x00AE86)
.setThumbnail(message.author.displayAvatarURL())
.setAuthor(msg.author.tag, msg.author.displayAvatarURL())
.setDescription(message.content)
.setTimestamp(message.createdAt)
.setFooter(`ID: ${message.id}`)
.addField(' Jump', message.url);
return msg.embed(embed);
}
};
@@ -6,7 +6,7 @@ module.exports = class ScrabbleScoreCommand extends Command {
super(client, {
name: 'scrabble-score',
aliases: ['scrabble'],
group: 'search',
group: 'number-edit',
memberName: 'scrabble-score',
description: 'Responds with the scrabble score of a word.',
args: [
-42
View File
@@ -1,42 +0,0 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
const { CLEVERBOT_KEY } = process.env;
module.exports = class CleverbotCommand extends Command {
constructor(client) {
super(client, {
name: 'cleverbot',
aliases: ['clevs'],
group: 'other',
memberName: 'cleverbot',
description: 'Chat with Cleverbot.',
details: 'Only the bot owner(s) may use this command.',
ownerOnly: true,
args: [
{
key: 'message',
prompt: 'What do you want to say to Cleverbot?',
type: 'string'
}
]
});
this.convos = new Map();
}
async run(msg, { message }) {
try {
const { body } = await request
.get('https://www.cleverbot.com/getreply')
.query({
key: CLEVERBOT_KEY,
cs: this.convos.get(msg.channel.id),
input: message
});
this.convos.set(msg.channel.id, body.cs);
return msg.reply(body.output);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
};
+2 -1
View File
@@ -15,7 +15,8 @@ module.exports = class AdviceSlipCommand extends Command {
async run(msg) {
try {
const { text } = await request.get('http://api.adviceslip.com/advice');
return msg.say(JSON.parse(text).slip.advice);
const body = JSON.parse(text);
return msg.say(`${body.slip.advice} (#${body.slip.slip_id})`);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
-51
View File
@@ -1,51 +0,0 @@
const Command = require('../../structures/Command');
const { MessageEmbed } = require('discord.js');
const request = require('node-superfetch');
const { shorten } = require('../../util/Util');
const { NYTIMES_KEY } = process.env;
module.exports = class NewYorkTimesCommand extends Command {
constructor(client) {
super(client, {
name: 'new-york-times',
aliases: ['ny-times', 'new-york-times-article', 'ny-times-article'],
group: 'random',
memberName: 'new-york-times',
description: 'Searches the New York Times for your query.',
clientPermissions: ['EMBED_LINKS'],
args: [
{
key: 'query',
prompt: 'What do you want to search for articles about?',
type: 'string',
default: ''
}
]
});
}
async run(msg, { query }) {
try {
const fetch = request
.get('https://api.nytimes.com/svc/search/v2/articlesearch.json')
.query({
'api-key': NYTIMES_KEY,
sort: 'newest'
});
if (query) fetch.query({ q: query });
const { body } = await fetch;
if (!body.response.docs.length) return msg.say('Could not find any results');
const data = body.response.docs[Math.floor(Math.random() * body.response.docs.length)];
const embed = new MessageEmbed()
.setColor(0xF6F6F6)
.setAuthor('New York Times', 'https://i.imgur.com/ZbuTWwO.png', 'https://www.nytimes.com/')
.setURL(data.web_url)
.setTitle(data.headline.main)
.setDescription(shorten(data.snippet))
.addField(' Publish Date', new Date(data.pub_date).toDateString(), true);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
};
-42
View File
@@ -1,42 +0,0 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
module.exports = class DanbooruCommand extends Command {
constructor(client) {
super(client, {
name: 'danbooru',
aliases: ['danbooru-image'],
group: 'search',
memberName: 'danbooru',
description: 'Responds with an image from Danbooru, with optional query.',
nsfw: true,
args: [
{
key: 'query',
prompt: 'What image would you like to search for?',
type: 'string',
default: '',
validate: query => {
if (!query.includes(' ')) return true;
return 'Invalid query, please only search for one tag at a time.';
}
}
]
});
}
async run(msg, { query }) {
try {
const { body } = await request
.get('https://danbooru.donmai.us/posts.json')
.query({
tags: `${query} order:random`,
limit: 1
});
if (!body.length || !body[0].file_url) return msg.say('Could not find any results.');
return msg.say(body[0].file_url);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
};
+20 -9
View File
@@ -21,18 +21,29 @@ module.exports = class DerpibooruCommand extends Command {
async run(msg, { query }) {
try {
const search = await request
.get('https://derpibooru.org/search.json')
.query({
q: query,
random_image: 1
});
if (!search.body) return msg.say('Could not find any results.');
const { body } = await request.get(`https://derpibooru.org/images/${search.body.id}.json`);
return msg.say(`https:${body.representations.full}`);
const id = await this.search(query);
if (!id) return msg.say('Could not find any results.');
const url = await this.fetchImage(id);
return msg.say(url);
} catch (err) {
if (err.status === 404) return msg.say('Could not find any results.');
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
async search(query) {
const { body } = await request
.get('https://derpibooru.org/search.json')
.query({
q: query,
random_image: 1
});
if (!body) return null;
return body.id;
}
async fetchImage(id) {
const { body } = await request.get(`https://derpibooru.org/images/${id}.json`);
return `${body.representations.full}`;
}
};
+1 -1
View File
@@ -36,7 +36,7 @@ module.exports = class DictionaryCommand extends Command {
const data = body[0];
return msg.say(stripIndents`
**${data.word}**
(${data.partOfSpeech || '???'}) ${data.text}
(${data.partOfSpeech || 'unknown'}) ${data.text}
`);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+1
View File
@@ -39,6 +39,7 @@ module.exports = class DiscordJSDocsCommand extends Command {
const { body } = await request
.get(`https://djsdocs.sorta.moe/${project}/${branch}/embed`)
.query({ q: query });
if (!body) return msg.say('Could not find any results.');
return msg.embed(body);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
-66
View File
@@ -1,66 +0,0 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
const { MessageEmbed } = require('discord.js');
const ratings = {
EC: 'Early Childhood',
E: 'Everyone',
E10plus: 'Everyone 10+',
T: 'Teen',
M: 'Mature',
AO: 'Adults Only'
};
module.exports = class ESRBCommand extends Command {
constructor(client) {
super(client, {
name: 'esrb',
aliases: ['esrb-rating'],
group: 'search',
memberName: 'esrb',
description: 'Searches ESRB for your query.',
args: [
{
key: 'query',
prompt: 'What game would you like to get the rating of?',
type: 'string'
}
]
});
}
async run(msg, { query }) {
try {
const data = await this.fetchRating(query);
const embed = new MessageEmbed()
.setColor(0x231F20)
.setAuthor('ESRB', 'https://i.imgur.com/6KAG7gD.png', 'http://www.esrb.org/')
.setTitle(data.title)
.setURL(data.url)
.setThumbnail(data.ratingImage)
.addField(' Rating', ratings[data.rating]);
return msg.embed(embed);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
async fetchRating(query) {
const { text, url } = await request
.get('http://www.esrb.org/ratings/search.aspx')
.query({
from: 'home',
titleOrPublisher: query
});
const title = text.match(/<strong name="title">(.+)<\/strong>/);
if (!title) return null;
const rating = text.match(
/https:\/\/esrbstorage.blob.core.windows.net\/esrbcontent\/images\/(EC|E|E10plus|T|M|AO).png/
);
return {
title: title[1].trim(),
rating: rating[1],
ratingImage: rating[0],
url
};
}
};
-42
View File
@@ -1,42 +0,0 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
module.exports = class GelbooruCommand extends Command {
constructor(client) {
super(client, {
name: 'gelbooru',
aliases: ['gelbooru-image'],
group: 'search',
memberName: 'gelbooru',
description: 'Responds with an image from Gelbooru, with optional query.',
nsfw: true,
args: [
{
key: 'query',
prompt: 'What image would you like to search for?',
type: 'string',
default: ''
}
]
});
}
async run(msg, { query }) {
try {
const { body } = await request
.get('https://gelbooru.com/index.php')
.query({
page: 'dapi',
s: 'post',
q: 'index',
json: 1,
tags: query,
limit: 200
});
if (!body) return msg.say('Could not find any results.');
return msg.say(body[Math.floor(Math.random() * body.length)].file_url);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
};
+1 -1
View File
@@ -22,7 +22,7 @@ module.exports = class HttpCatCommand extends Command {
async run(msg, { code }) {
try {
const { body, headers } = await request.get(`https://http.cat/${code}.jpg`);
if (headers['content-type'] === 'text/html') return msg.say('Could not find any results.');
if (headers['content-type'].includes('text/html')) return msg.say('Could not find any results.');
return msg.say({ files: [{ attachment: body, name: `${code}.jpg` }] });
} catch (err) {
if (err.status === 404) return msg.say('Could not find any results.');
-38
View File
@@ -1,38 +0,0 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
module.exports = class KonachanCommand extends Command {
constructor(client) {
super(client, {
name: 'konachan',
aliases: ['konachan-image'],
group: 'search',
memberName: 'konachan',
description: 'Responds with an image from Konachan, with optional query.',
nsfw: true,
args: [
{
key: 'query',
prompt: 'What image would you like to search for?',
type: 'string',
default: ''
}
]
});
}
async run(msg, { query }) {
try {
const { body } = await request
.get('https://konachan.net/post.json')
.query({
tags: `${query} order:random`,
limit: 1
});
if (!body.length || !body[0].file_url) return msg.say('Could not find any results.');
return msg.say(`https:${body[0].file_url}`);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
};
+3 -4
View File
@@ -50,13 +50,12 @@ module.exports = class NeopetsItemCommand extends Command {
if (!id) return null;
const price = text.match(/>([0-9,]+) (NP|NC)</);
const url = `https://items.jellyneo.net/item/${id[1]}/`;
const details = await request.get(url);
const detailsText = details.text;
const details = (await request.get(url)).text;
return {
id: id[1],
url,
name: detailsText.match(/<h1>(.+)<\/h1>/)[1],
details: detailsText.match(/<em>(.+)<\/em>/)[1],
name: details.match(/<h1>(.+)<\/h1>/)[1],
details: details.match(/<em>(.+)<\/em>/)[1],
image: `https://items.jellyneo.net/assets/imgs/items/${id[1]}.gif`,
price: price ? Number.parseInt(price[1].replace(/,/g, ''), 10) : null,
currency: price ? price[2] : null
+26 -17
View File
@@ -24,26 +24,18 @@ module.exports = class RottenTomatoesCommand extends Command {
async run(msg, { query }) {
try {
const search = await request
.get('https://www.rottentomatoes.com/api/private/v2.0/search/')
.query({
limit: 10,
q: query
});
if (!search.body.movies.length) return msg.say('Could not find any results.');
const find = search.body.movies.find(m => m.name.toLowerCase() === query.toLowerCase()) || search.body.movies[0];
const urlID = find.url.replace('/m/', '');
const { text } = await request.get(`https://www.rottentomatoes.com/api/private/v1.0/movies/${urlID}`);
const body = JSON.parse(text);
const criticScore = body.ratingSummary.allCritics;
const audienceScore = body.ratingSummary.audience;
const id = await this.search(query);
if (!id) return msg.say('Could not find any results.');
const data = await this.fetchMovie(id);
const criticScore = data.ratingSummary.allCritics;
const audienceScore = data.ratingSummary.audience;
const embed = new MessageEmbed()
.setColor(0xFFEC02)
.setTitle(`${body.title} (${body.year})`)
.setURL(`https://www.rottentomatoes.com${body.url}`)
.setTitle(`${data.title} (${data.year})`)
.setURL(`https://www.rottentomatoes.com${data.url}`)
.setAuthor('Rotten Tomatoes', 'https://i.imgur.com/Sru8mZ3.jpg', 'https://www.rottentomatoes.com/')
.setDescription(shorten(body.ratingSummary.consensus))
.setThumbnail(body.posters.original)
.setDescription(shorten(data.ratingSummary.consensus))
.setThumbnail(data.posters.original)
.addField(' Critic Score', criticScore.meterValue ? `${criticScore.meterValue}%` : '???', true)
.addField(' Audience Score', audienceScore.meterScore ? `${audienceScore.meterScore}%` : '???', true);
return msg.embed(embed);
@@ -51,4 +43,21 @@ module.exports = class RottenTomatoesCommand extends Command {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
async search(query) {
const { body } = await request
.get('https://www.rottentomatoes.com/api/private/v2.0/search/')
.query({
limit: 10,
q: query
});
if (!body.movies.length) return null;
const find = body.movies.find(m => m.name.toLowerCase() === query.toLowerCase()) || body.movies[0];
return find.url.replace('/m/', '');
}
async fetchMovie(id) {
const { text } = await request.get(`https://www.rottentomatoes.com/api/private/v1.0/movies/${id}`);
return JSON.parse(text);
}
};
-2
View File
@@ -14,7 +14,6 @@ module.exports = class RuleOfTheInternetCommand extends Command {
key: 'rule',
prompt: 'Which rule would you like to view?',
type: 'integer',
default: '',
min: 1,
max: rules.length
}
@@ -23,7 +22,6 @@ module.exports = class RuleOfTheInternetCommand extends Command {
}
run(msg, { rule }) {
if (!rule) return msg.say({ files: ['https://i.imgur.com/vGw29EQ.jpg'] });
return msg.say(`**Rule #${rule}**: ${rules[rule - 1]}`);
}
};
-44
View File
@@ -1,44 +0,0 @@
const Command = require('../../structures/Command');
const request = require('node-superfetch');
module.exports = class Rule34Command extends Command {
constructor(client) {
super(client, {
name: 'rule34',
aliases: ['rule34-image', 'r34'],
group: 'search',
memberName: 'rule34',
description: 'Responds with an image from Rule34, with optional query.',
nsfw: true,
args: [
{
key: 'query',
prompt: 'What image would you like to search for?',
type: 'string',
default: ''
}
]
});
}
async run(msg, { query }) {
try {
const { text } = await request
.get('https://rule34.xxx/index.php')
.query({
page: 'dapi',
s: 'post',
q: 'index',
json: 1,
tags: query,
limit: 200
});
if (!text) return msg.say('Could not find any results.');
const body = JSON.parse(text);
const data = body[Math.floor(Math.random() * body.length)];
return msg.say(`https://rule34.xxx/images/${data.directory}/${data.image}`);
} catch (err) {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
};
+23 -14
View File
@@ -23,19 +23,9 @@ module.exports = class SteamCommand extends Command {
async run(msg, { query }) {
try {
const search = await request
.get('https://store.steampowered.com/api/storesearch')
.query({
cc: 'us',
l: 'en',
term: query
});
if (!search.body.items.length) return msg.say('Could not find any results.');
const { id, tiny_image } = search.body.items[0];
const { body } = await request
.get('https://store.steampowered.com/api/appdetails')
.query({ appids: id });
const { data } = body[id.toString()];
const id = await this.search(query);
if (!id) return msg.say('Could not find any results.');
const data = await this.fetchGame(id);
const current = data.price_overview ? `$${data.price_overview.final / 100}` : 'Free';
const original = data.price_overview ? `$${data.price_overview.initial / 100}` : 'Free';
const price = current === original ? current : `~~${original}~~ ${current}`;
@@ -50,7 +40,7 @@ module.exports = class SteamCommand extends Command {
.setAuthor('Steam', 'https://i.imgur.com/xxr2UBZ.png', 'http://store.steampowered.com/')
.setTitle(data.name)
.setURL(`http://store.steampowered.com/app/${data.steam_appid}`)
.setThumbnail(tiny_image)
.setThumbnail(data.header_image)
.addField(' Price', price, true)
.addField(' Metascore', data.metacritic ? data.metacritic.score : '???', true)
.addField(' Recommendations', data.recommendations ? data.recommendations.total : '???', true)
@@ -64,4 +54,23 @@ module.exports = class SteamCommand extends Command {
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
}
}
async search(query) {
const { body } = await request
.get('https://store.steampowered.com/api/storesearch')
.query({
cc: 'us',
l: 'en',
term: query
});
if (!body.items.length) return null;
return body.items[0].id;
}
async fetchGame(id) {
const { body } = await request
.get('https://store.steampowered.com/api/appdetails')
.query({ appids: id });
return body[id.toString()].data;
}
};
+24 -13
View File
@@ -30,27 +30,38 @@ module.exports = class WikiaCommand extends Command {
async run(msg, { wiki, query }) {
try {
const search = await request
.get(`http://${wiki}.wikia.com/api/v1/Search/List/`)
.query({
query,
limit: 1,
namespaces: 0
});
const { body } = await request
.get(`http://${wiki}.wikia.com/api/v1/Articles/AsSimpleJson/`)
.query({ id: search.body.items[0].id });
const data = body.sections[0];
const { id, url } = await this.search(wiki, query);
const data = await this.fetchArticle(wiki, id);
const embed = new MessageEmbed()
.setColor(0x002D54)
.setTitle(data.title)
.setURL(search.body.items[0].url)
.setURL(url)
.setAuthor('Wikia', 'https://i.imgur.com/15A34JT.png', 'http://www.wikia.com/fandom')
.setDescription(shorten(data.content.map(section => section.text).join('\n\n')))
.setThumbnail(data.images.length ? data.images[0].src : null);
return msg.embed(embed);
} catch (err) {
return msg.say('Could not find any results.');
if (err.status === 404) return msg.say('Could not find any results');
return msg.say(`Oh no, an error occurred: \`${err.message}\`. Perhaps you entered an invalid wiki?`);
}
}
async search(wiki, query) {
const { body } = await request
.get(`https://${wiki}.wikia.com/api/v1/Search/List/`)
.query({
query,
limit: 1,
namespaces: 0
});
const data = body.items[0];
return { id: data.id, url: data.url };
}
async fetchArticle(wiki, id) {
const { body } = await request
.get(`https://${wiki}.wikia.com/api/v1/Articles/AsSimpleJson/`)
.query({ id });
return body.sections[0];
}
};
-29
View File
@@ -1,29 +0,0 @@
const Command = require('../../structures/Command');
const { MessageEmbed } = require('discord.js');
const { stripIndents } = require('common-tags');
module.exports = class NitroCommand extends Command {
constructor(client) {
super(client, {
name: 'nitro',
aliases: ['discord-nitro', 'nitro-message', 'nitro-msg'],
group: 'single',
memberName: 'nitro',
description: 'Sends the "This message can only be viewed by users with Discord Nitro." message.',
clientPermissions: ['EMBED_LINKS']
});
}
run(msg) {
const embed = new MessageEmbed()
.setAuthor('Discord Nitro', 'https://i.imgur.com/DKaY8fV.jpg', 'https://discordapp.com/nitro')
.setThumbnail('https://i.imgur.com/DKaY8fV.jpg')
.setColor(0x8395D3)
.setTimestamp()
.setDescription(stripIndents`
This message can only be viewed by users with Discord Nitro.
[More Information](https://discordapp.com/nitro)
`);
return msg.embed(embed);
}
};
-27
View File
@@ -1,27 +0,0 @@
const Command = require('../../structures/Command');
module.exports = class BCommand extends Command {
constructor(client) {
super(client, {
name: '🅱',
group: 'text-edit',
memberName: '🅱',
description: 'Replaces b with 🅱.',
args: [
{
key: 'text',
prompt: 'What text would you like to 🅱?',
type: 'string',
validate: text => {
if (text.replace(/b/gi, '🅱').length < 2000) return true;
return 'Invalid text, your text is too long.';
}
}
]
});
}
run(msg, { text }) {
return msg.say(text.replace(/b/gi, '🅱'));
}
};
+1 -1
View File
@@ -11,7 +11,7 @@ module.exports = class ChangelogCommand extends Command {
aliases: ['updates', 'commits'],
group: 'util',
memberName: 'changelog',
description: 'Responds with Xiao\'s latest 10 commits.',
description: 'Responds with the bot\'s latest 10 commits.',
guarded: true
});
}
+2 -2
View File
@@ -8,14 +8,14 @@ module.exports = class DonateCommand extends Command {
aliases: ['patreon', 'paypal'],
group: 'util',
memberName: 'donate',
description: 'Responds with Xiao\'s donation links.',
description: 'Responds with the bot\'s donation links.',
guarded: true
});
}
run(msg) {
return msg.say(stripIndents`
Contribute to Xiao development!
Contribute to development!
<https://www.patreon.com/dragonfire535>
<https://paypal.me/dragonfire535>
`);
+4 -2
View File
@@ -26,11 +26,13 @@ module.exports = class HelpCommand extends Command {
if (!command) {
const embed = new MessageEmbed()
.setTitle('Command List')
.setDescription(`Use ${msg.usage('<command>')} to view detailed information about a command.`)
.setColor(0x00AE86)
.setFooter(`${this.client.registry.commands.size} Commands`);
for (const group of this.client.registry.groups.values()) {
embed.addField(` ${group.name}`, group.commands.map(cmd => cmd.name).join(', ') || 'None');
embed.addField(
` ${group.name}`,
group.commands.map(cmd => `\`${cmd.name}\``).join(', ') || 'None'
);
}
try {
const msgs = [];
+5 -1
View File
@@ -1,5 +1,6 @@
const Command = require('../../structures/Command');
const { stripIndents } = require('common-tags');
const { XIAO_GITHUB_REPO_NAME, XIAO_GITHUB_REPO_USERNAME } = process.env;
module.exports = class InviteCommand extends Command {
constructor(client) {
@@ -8,7 +9,7 @@ module.exports = class InviteCommand extends Command {
aliases: ['join'],
group: 'util',
memberName: 'invite',
description: 'Responds with Xiao\'s invite links.',
description: 'Responds with the bot\'s invite links.',
guarded: true
});
}
@@ -17,6 +18,9 @@ module.exports = class InviteCommand extends Command {
return msg.say(stripIndents`
You cannot invite me to your server, but you can join my home server to use me:
${this.client.options.invite || 'Coming soon...'}
You can also self-host me if you prefer:
<https://github.com/${XIAO_GITHUB_REPO_USERNAME}/${XIAO_GITHUB_REPO_NAME}>
`);
}
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "xiao",
"version": "86.0.0",
"version": "87.0.0",
"description": "Your personal server companion.",
"main": "Xiao.js",
"scripts": {
+2 -4
View File
@@ -1,12 +1,10 @@
const { Command } = require('discord.js-commando');
class XiaoCommand extends Command {
module.exports = class XiaoCommand extends Command {
constructor(client, info) {
super(client, info);
this.argsSingleQuotes = info.argsSingleQuotes || false;
this.throttling = info.throttling || { usages: 1, duration: 2 };
}
}
module.exports = XiaoCommand;
};
+2 -4
View File
@@ -1,6 +1,6 @@
const { ArgumentType } = require('discord.js-commando');
class AvatarArgumentType extends ArgumentType {
module.exports = class AvatarArgumentType extends ArgumentType {
constructor(client) {
super(client, 'avatar');
}
@@ -13,6 +13,4 @@ class AvatarArgumentType extends ArgumentType {
const user = await this.client.registry.types.get('user').parse(value, msg, arg);
return user.displayAvatarURL({ format: 'png', size: 512 });
}
}
module.exports = AvatarArgumentType;
};
+13 -15
View File
@@ -1,7 +1,7 @@
const { ArgumentType, util: { disambiguation } } = require('discord.js-commando');
const { escapeMarkdown } = require('discord.js');
class EmojiArgumentType extends ArgumentType {
module.exports = class EmojiArgumentType extends ArgumentType {
constructor(client) {
super(client, 'emoji');
}
@@ -11,13 +11,13 @@ class EmojiArgumentType extends ArgumentType {
if (matches && msg.client.emojis.has(matches[2])) return true;
if (!msg.guild) return false;
const search = value.toLowerCase();
let emojis = msg.guild.emojis.filterArray(nameFilterInexact(search));
if (!emojis.length) return false;
if (emojis.length === 1) return true;
let emojis = msg.guild.emojis.filter(nameFilterInexact(search));
if (!emojis.size) return false;
if (emojis.size === 1) return true;
const exactEmojis = emojis.filter(nameFilterExact(search));
if (exactEmojis.length === 1) return true;
if (exactEmojis.length > 0) emojis = exactEmojis;
return emojis.length <= 15
if (exactEmojis.size === 1) return true;
if (exactEmojis.size > 0) emojis = exactEmojis;
return emojis.size <= 15
? `${disambiguation(emojis.map(emoji => escapeMarkdown(emoji.name)), 'emojis', null)}\n`
: 'Multiple emojis found. Please be more specific.';
}
@@ -26,11 +26,11 @@ class EmojiArgumentType extends ArgumentType {
const matches = value.match(/^(?:<a?:([a-zA-Z0-9_]+):)?([0-9]+)>?$/);
if (matches) return msg.client.emojis.get(matches[2]) || null;
const search = value.toLowerCase();
const emojis = msg.guild.emojis.filterArray(nameFilterInexact(search));
if (!emojis.length) return null;
if (emojis.length === 1) return emojis[0];
const exactEmojis = emojis.filterArray(nameFilterExact(search));
if (exactEmojis.length === 1) return exactEmojis[0];
const emojis = msg.guild.emojis.filter(nameFilterInexact(search));
if (!emojis.size) return null;
if (emojis.size === 1) return emojis.first();
const exactEmojis = emojis.filter(nameFilterExact(search));
if (exactEmojis.size === 1) return exactEmojis.first();
return null;
}
}
@@ -41,6 +41,4 @@ function nameFilterExact(search) {
function nameFilterInexact(search) {
return thing => thing.name.toLowerCase().includes(search);
}
module.exports = EmojiArgumentType;
};
+2 -4
View File
@@ -1,6 +1,6 @@
const { ArgumentType } = require('discord.js-commando');
class ImageArgumentType extends ArgumentType {
module.exports = class ImageArgumentType extends ArgumentType {
constructor(client) {
super(client, 'image');
}
@@ -19,6 +19,4 @@ class ImageArgumentType extends ArgumentType {
isEmpty(value, msg) {
return msg.attachments.size === 0;
}
}
module.exports = ImageArgumentType;
};
+2 -4
View File
@@ -1,7 +1,7 @@
const { ArgumentType } = require('discord.js-commando');
const months = require('../assets/json/month');
class MonthArgumentType extends ArgumentType {
module.exports = class MonthArgumentType extends ArgumentType {
constructor(client) {
super(client, 'month');
}
@@ -18,6 +18,4 @@ class MonthArgumentType extends ArgumentType {
if (!Number.isNaN(num)) return num;
return months.indexOf(value.toLowerCase()) + 1;
}
}
module.exports = MonthArgumentType;
};
+2 -4
View File
@@ -1,4 +1,4 @@
class CanvasUtil {
module.exports = class CanvasUtil {
static greyscale(ctx, x, y, width, height) {
const data = ctx.getImageData(x, y, width, height);
for (let i = 0; i < data.data.length; i += 4) {
@@ -93,6 +93,4 @@ class CanvasUtil {
while (ctx.measureText(text).width > maxWidth) text = text.substr(0, text.length - 1);
return shorten ? `${text}...` : text;
}
}
module.exports = CanvasUtil;
};
+2 -4
View File
@@ -5,7 +5,7 @@ const yes = ['yes', 'y', 'ye', 'yeah', 'yup', 'yea'];
const no = ['no', 'n', 'nah', 'nope'];
const { SUCCESS_EMOJI_ID } = process.env;
class Util {
module.exports = class Util {
static delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
@@ -125,6 +125,4 @@ class Util {
if (no.includes(choice)) return false;
return false;
}
}
module.exports = Util;
};