diff --git a/.env.example b/.env.example
index 6d5fa308..5f73afe5 100644
--- a/.env.example
+++ b/.env.example
@@ -38,7 +38,6 @@ GOOGLE_KEY=
GOV_KEY=
SPOTIFY_KEY=
SPOTIFY_SECRET=
-USPS_USERID=
WEBSTER_KEY=
XIAO_GITHUB_REPO_NAME=
XIAO_GITHUB_REPO_USERNAME=
diff --git a/assets/json/google-feud.json b/assets/json/google-feud.json
new file mode 100644
index 00000000..7b08399a
--- /dev/null
+++ b/assets/json/google-feud.json
@@ -0,0 +1,101 @@
+[
+ "Are cats",
+ "Are dogs",
+ "Are birds",
+ "Do cats",
+ "Do dogs",
+ "Do birds",
+ "Am I",
+ "Is Google",
+ "Is it bad to",
+ "What is the best way to",
+ "Can cats",
+ "Can I",
+ "Can you",
+ "Is it okay to",
+ "Will I die if",
+ "Does the world hate",
+ "Does everyone hate",
+ "Can you code",
+ "JavaScript is",
+ "Schools are",
+ "Is Discord",
+ "What is",
+ "Where is",
+ "Did dinosaurs",
+ "When will",
+ "Is anime",
+ "What anime is",
+ "Am I part",
+ "Does Google know",
+ "Is the world",
+ "What game is",
+ "What game has",
+ "Is net neutrality",
+ "What is the worst",
+ "What is the best",
+ "Is Kingdom Hearts",
+ "Can humans",
+ "Is chocolate",
+ "Are cameras",
+ "Who is the most",
+ "Who is the least",
+ "Am I going to pass",
+ "Google is",
+ "Can you eat",
+ "Eat pant",
+ "Are computers",
+ "Is it legal to",
+ "Am I allowed to",
+ "Is it possible to",
+ "Can I have",
+ "Is Neopets",
+ "Can I go",
+ "Can you die from",
+ "Should I",
+ "Will I die",
+ "Do people hate",
+ "Do people love",
+ "Am I in",
+ "Am I going to",
+ "Are my friends",
+ "Does my girlfriend",
+ "Does my boyfriend",
+ "Is my girlfriend",
+ "Is my boyfriend",
+ "What is the worst way to",
+ "Is there a limit on",
+ "What is the maximum",
+ "What is the minimum",
+ "Is the government",
+ "Are LEGOs",
+ "Memes are",
+ "Are memes",
+ "How do I get to",
+ "What website has",
+ "Is Discord better",
+ "How do I",
+ "How do you",
+ "Is it healthy to",
+ "Is it harmful to",
+ "Google",
+ "What is the best site for",
+ "Is it illegal to",
+ "Are lawyers",
+ "Does Discord",
+ "Can Discord bots",
+ "Who is the richest",
+ "Is the internet",
+ "Should I stay",
+ "On what day is",
+ "Do you need money to get",
+ "Are cats really",
+ "Are dogs really",
+ "Are there more",
+ "Is Twitter",
+ "Can I play",
+ "Is it right to",
+ "Is it wrong to",
+ "Discord is",
+ "Is 100"
+]
diff --git a/commands/games-sp/google-feud.js b/commands/games-sp/google-feud.js
new file mode 100644
index 00000000..8311a1af
--- /dev/null
+++ b/commands/games-sp/google-feud.js
@@ -0,0 +1,96 @@
+const Command = require('../../framework/Command');
+const request = require('node-superfetch');
+const { MessageEmbed } = require('discord.js');
+const questions = require('../../assets/json/google-feud');
+const { formatNumber } = require('../../util/Util');
+
+module.exports = class GoogleFeudCommand extends Command {
+ constructor(client) {
+ super(client, {
+ name: 'google-feud',
+ group: 'games-sp',
+ memberName: 'google-feud',
+ description: 'Attempt to determine the top suggestions for a Google search.',
+ credit: [
+ {
+ name: 'Google',
+ url: 'https://www.google.com/',
+ reason: 'Autofill API'
+ },
+ {
+ name: 'Google Feud',
+ url: 'http://www.googlefeud.com/',
+ reason: 'Original Game'
+ }
+ ]
+ });
+ }
+
+ async run(msg) {
+ const current = this.client.games.get(msg.channel.id);
+ if (current) return msg.reply(`Please wait until the current game of \`${current.name}\` is finished.`);
+ this.client.games.set(msg.channel.id, { name: this.name });
+ try {
+ const question = questions[Math.floor(Math.random() * questions.length)];
+ const suggestions = await this.fetchSuggestions(question);
+ if (!suggestions) return msg.say('Could not find any results.');
+ const display = new Array(suggestions.length).fill('???');
+ let tries = 4;
+ let score = 0;
+ while (display.includes('???') && tries) {
+ const embed = this.makeEmbed(question, tries, suggestions, display);
+ await msg.embed(embed);
+ const msgs = await msg.channel.awaitMessages(res => res.author.id === msg.author.id, {
+ max: 1,
+ time: 30000
+ });
+ if (!msgs.size) {
+ await msg.say('Time is up!');
+ break;
+ }
+ const choice = msgs.first().content.toLowerCase();
+ if (suggestions.includes(choice)) {
+ score += 10000 - (suggestions.indexOf(choice) * 1000);
+ display[suggestions.indexOf(choice)] = choice;
+ } else {
+ --tries;
+ }
+ }
+ this.client.games.delete(msg.channel.id);
+ if (!display.includes('???')) {
+ return msg.say(`You win! Nice job, master of Google!\n**Final Score: $${formatNumber(score)}**`);
+ }
+ const final = this.makeEmbed(question, tries, suggestions, suggestions);
+ return msg.say(`Better luck next time!\n**Final Score: $${formatNumber(score)}**`, { embeds: [final] });
+ } catch (err) {
+ this.client.games.delete(msg.channel.id);
+ return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
+ }
+ }
+
+ async fetchSuggestions(question) {
+ const { text } = await request
+ .get('https://suggestqueries.google.com/complete/search')
+ .query({
+ client: 'firefox',
+ q: question
+ });
+ const suggestions = JSON.parse(text)[1]
+ .filter(suggestion => suggestion.toLowerCase() !== question.toLowerCase());
+ if (!suggestions.length) return null;
+ return suggestions.map(suggestion => suggestion.toLowerCase().replace(question.toLowerCase(), '').trim());
+ }
+
+ makeEmbed(question, tries, suggestions, display) {
+ const embed = new MessageEmbed()
+ .setColor(0x005AF0)
+ .setTitle(`${question}...?`)
+ .setDescription('Type the choice you think is a suggestion _without_ the question.')
+ .setFooter(`${tries} ${tries === 1 ? 'try' : 'tries'} remaining!`);
+ for (let i = 0; i < suggestions.length; i++) {
+ const num = formatNumber(10000 - (i * 1000));
+ embed.addField(`❯ ${num}`, display[i], true);
+ }
+ return embed;
+ }
+};
diff --git a/commands/other/strawpoll.js b/commands/other/strawpoll.js
deleted file mode 100644
index e1fbe800..00000000
--- a/commands/other/strawpoll.js
+++ /dev/null
@@ -1,59 +0,0 @@
-const Command = require('../../framework/Command');
-const { stripIndents } = require('common-tags');
-const request = require('node-superfetch');
-
-module.exports = class StrawpollCommand extends Command {
- constructor(client) {
- super(client, {
- name: 'strawpoll',
- aliases: ['poll'],
- group: 'other',
- memberName: 'strawpoll',
- description: 'Generates a Strawpoll with the options you provide.',
- credit: [
- {
- name: 'Straw Poll',
- url: 'https://www.strawpoll.me/',
- reason: 'API',
- reasonURL: 'https://github.com/strawpoll/strawpoll/wiki/API'
- }
- ],
- args: [
- {
- key: 'title',
- prompt: 'What would you like the title of the Strawpoll to be?',
- type: 'string',
- max: 200
- },
- {
- key: 'options',
- prompt: 'What options do you want to be able to pick from? You may have a maximum of 30.',
- type: 'string',
- infinite: true,
- max: 140
- }
- ]
- });
- }
-
- async run(msg, { title, options }) {
- if (options.length < 2) return msg.reply('Please provide more than one choice.');
- if (options.length > 31) return msg.reply('Please provide thirty or less choices.');
- try {
- const { body } = await request
- .post('https://www.strawpoll.me/api/v2/polls')
- .set({ 'Content-Type': 'application/json' })
- .send({
- title,
- options,
- captcha: true
- });
- return msg.say(stripIndents`
- ${body.title}
- http://www.strawpoll.me/${body.id}
- `);
- } catch (err) {
- return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
- }
- }
-};
diff --git a/commands/search/jisho.js b/commands/search/jisho.js
deleted file mode 100644
index bda50a44..00000000
--- a/commands/search/jisho.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const Command = require('../../framework/Command');
-const request = require('node-superfetch');
-const { stripIndents } = require('common-tags');
-
-module.exports = class JishoCommand extends Command {
- constructor(client) {
- super(client, {
- name: 'jisho',
- aliases: ['japanese-dictionary', 'define-japanese', 'define-jpn'],
- group: 'search',
- memberName: 'jisho',
- description: 'Defines a word, but with Japanese.',
- credit: [
- {
- name: 'Jisho',
- url: 'https://jisho.org/',
- reason: 'API'
- }
- ],
- args: [
- {
- key: 'word',
- prompt: 'What word would you like to look up?',
- type: 'string'
- }
- ]
- });
- }
-
- async run(msg, { word }) {
- try {
- const { body } = await request
- .get('http://jisho.org/api/v1/search/words')
- .query({ keyword: word });
- if (!body.data.length) return msg.say('Could not find any results.');
- const data = body.data[0];
- return msg.say(stripIndents`
- **${data.japanese[0].word || data.japanese[0].reading}**
- ${data.senses[0].english_definitions.join(', ')}
- `);
- } catch (err) {
- return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
- }
- }
-};
diff --git a/commands/search/osu.js b/commands/search/osu.js
deleted file mode 100644
index 81c3e8ca..00000000
--- a/commands/search/osu.js
+++ /dev/null
@@ -1,64 +0,0 @@
-const Command = require('../../framework/Command');
-const { MessageEmbed } = require('discord.js');
-const request = require('node-superfetch');
-const { formatNumber } = require('../../util/Util');
-const { OSU_KEY } = process.env;
-
-module.exports = class OsuCommand extends Command {
- constructor(client) {
- super(client, {
- name: 'osu',
- group: 'search',
- memberName: 'osu',
- description: 'Responds with information on an osu! user.',
- clientPermissions: ['EMBED_LINKS'],
- credit: [
- {
- name: 'osu!',
- url: 'https://osu.ppy.sh/home',
- reason: 'API',
- reasonURL: 'https://github.com/ppy/osu-api/wiki'
- }
- ],
- args: [
- {
- key: 'user',
- prompt: 'What user would you like to get information on?',
- type: 'string'
- }
- ]
- });
- }
-
- async run(msg, { user }) {
- try {
- const { body } = await request
- .get('https://osu.ppy.sh/api/get_user')
- .query({
- k: OSU_KEY,
- u: user,
- type: 'string'
- });
- if (!body.length) return msg.say('Could not find any results.');
- const data = body[0];
- const embed = new MessageEmbed()
- .setColor(0xFF66AA)
- .setAuthor('osu!', 'https://i.imgur.com/hWrw2Sv.png', 'https://osu.ppy.sh/')
- .addField('❯ Username', data.username, true)
- .addField('❯ ID', data.user_id, true)
- .addField('❯ Level', data.level || '???', true)
- .addField('❯ Accuracy', data.accuracy ? `${Math.round(data.accuracy)}%` : '???', true)
- .addField('❯ Rank', data.pp_rank ? formatNumber(data.pp_rank) : '???', true)
- .addField('❯ Play Count', data.playcount ? formatNumber(data.playcount) : '???', true)
- .addField('❯ Country', data.country || '???', true)
- .addField('❯ Ranked Score', data.ranked_score ? formatNumber(data.ranked_score) : '???', true)
- .addField('❯ Total Score', data.total_score ? formatNumber(data.total_score) : '???', true)
- .addField('❯ SS', data.count_rank_ss ? formatNumber(data.count_rank_ss) : '???', true)
- .addField('❯ S', data.count_rank_s ? formatNumber(data.count_rank_s) : '???', true)
- .addField('❯ A', data.count_rank_a ? formatNumber(data.count_rank_a) : '???', true);
- return msg.embed(embed);
- } catch (err) {
- return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
- }
- }
-};
diff --git a/commands/search/smash-bros.js b/commands/search/smash-bros.js
deleted file mode 100644
index 11d9e6c5..00000000
--- a/commands/search/smash-bros.js
+++ /dev/null
@@ -1,101 +0,0 @@
-const Command = require('../../framework/Command');
-const { Collection } = require('@discordjs/collection');
-const { MessageEmbed } = require('discord.js');
-const request = require('node-superfetch');
-
-module.exports = class SmashBrosCommand extends Command {
- constructor(client) {
- super(client, {
- name: 'smash-bros',
- aliases: ['super-smash-bros', 'ssb', 'smash-fighter', 'smash-bros-fighter', 'smash'],
- group: 'search',
- memberName: 'smash-bros',
- description: 'Responds with data for a Super Smash Bros. fighter.',
- clientPermissions: ['EMBED_LINKS'],
- credit: [
- {
- name: 'Nintendo',
- url: 'https://www.nintendo.com/',
- reason: 'Original "Super Smash Bros." Game, Fighter Data',
- reasonURL: 'https://www.smashbros.com/en_US/index.html'
- }
- ],
- args: [
- {
- key: 'query',
- prompt: 'What fighter would you like to get information for?',
- type: 'string'
- }
- ]
- });
-
- this.cache = new Collection();
- }
-
- async run(msg, { query }) {
- try {
- const fighters = await this.fetchFighters();
- const fighter = fighters.find(char => {
- const search = this.makeSlug(query).replace('_and_', '_&_');
- return search === char.slug || char.alias === search;
- });
- if (!fighter) return msg.say('Could not find any results.');
- const embed = new MessageEmbed()
- .setColor(fighter.color)
- .setTitle(fighter.name)
- .setURL(fighter.url)
- .setAuthor(
- 'Super Smash Bros. Ultimate',
- 'https://i.imgur.com/p407YZ5.jpg',
- 'https://www.smashbros.com/en_US/index.html'
- )
- .setDescription(fighter.dlc ? '_DLC Fighter_' : '')
- .setImage(fighter.image)
- .setThumbnail(fighter.logoImage)
- .setFooter(`Fighter ${fighter.number}`, fighter.smallImage);
- return msg.embed(embed);
- } catch (err) {
- return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
- }
- }
-
- async fetchFighters() {
- if (this.cache.size) return this.cache;
- const { body } = await request.get('https://www.smashbros.com/assets_v2/data/fighter.json');
- for (const fighter of body.fighters) {
- const data = {
- name: fighter.displayName.en_US.replaceAll('
', ''),
- alias: this.makeAlias(fighter.displayName.en_US),
- number: fighter.displayNum.replace('\'', 'E'),
- id: fighter.id,
- url: `https://www.smashbros.com/en_US/fighter/${fighter.url}.html`,
- image: `https://www.smashbros.com/assets_v2/img/fighter/${fighter.file}/main.png`,
- smallImage: `https://www.smashbros.com/assets_v2/img/fighter/pict/${fighter.file}.png`,
- logoImage: `https://www.smashbros.com/assets_v2/img/fighter/logo/${fighter.series}_en.png`,
- series: fighter.series,
- color: fighter.color,
- dlc: Boolean(fighter.dlc),
- slug: this.makeSlug(fighter.displayName.en_US)
- };
- this.cache.set(fighter.id, data);
- }
- setTimeout(() => this.cache.clear(), 8.64e+7);
- return this.cache;
- }
-
- makeSlug(name) {
- return name
- .replace(/\/.+/, '')
- .trim()
- .replaceAll('
', '')
- .replaceAll(' ', '_')
- .replace(/[^A-Z_&]/ig, '')
- .toLowerCase();
- }
-
- makeAlias(name) {
- const alias = name.match(/\/(.+)/, '');
- if (!alias) return null;
- return this.makeSlug(alias[1]);
- }
-};
diff --git a/commands/search/usps-tracking.js b/commands/search/usps-tracking.js
deleted file mode 100644
index b0472841..00000000
--- a/commands/search/usps-tracking.js
+++ /dev/null
@@ -1,75 +0,0 @@
-const Command = require('../../framework/Command');
-const request = require('node-superfetch');
-const { stripIndents } = require('common-tags');
-const { homepage } = require('../../package');
-const { USPS_USERID } = process.env;
-
-module.exports = class USPSTrackingCommand extends Command {
- constructor(client) {
- super(client, {
- name: 'usps-tracking',
- aliases: ['usps-track', 'usps'],
- group: 'search',
- memberName: 'usps-tracking',
- description: 'Gets tracking information for a package shipped via USPS.',
- credit: [
- {
- name: 'USPS',
- url: 'https://www.usps.com/',
- reason: 'API',
- reasonURL: 'https://www.usps.com/business/web-tools-apis/'
- }
- ],
- args: [
- {
- key: 'id',
- label: 'tracking id',
- prompt: 'What is the tracking ID of the package you would like to track?',
- type: 'string',
- validate: id => /^[0-9A-Z]+$/i.test(id)
- }
- ]
- });
- }
-
- async run(msg, { id }) {
- try {
- const data = await this.fetchStatus(id);
- if (!data) return msg.say('A status update is not yet available on your package. Check back soon.');
- return msg.say(stripIndents`
- **Tracking info for ${id}:**
- ${data.summary}
-
- Expected Delivery by: ${data.expected || 'N/A'}
- More Info:
- `);
- } catch (err) {
- return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
- }
- }
-
- async fetchStatus(id) {
- const { text } = await request
- .get('https://secure.shippingapis.com/ShippingApi.dll')
- .query({
- API: 'TrackV2',
- XML: stripIndents`
-
- 1
- 127.0.0.1
- ${homepage}
-
-
-
- `
- });
- if (text.includes('-2147219283')) return null;
- if (text.includes('')) throw new Error(text.match(/(.+)<\/Description>/i)[1].trim());
- const summary = text.match(/(.+)<\/StatusSummary>/i);
- const expected = text.match(/(.+)<\/ExpectedDeliveryDate>/i);
- return {
- summary: summary ? summary[1].trim() : null,
- expected: expected ? expected[1].trim() : null
- };
- }
-};