commit 57f9aa5b1b62b868873ae2f103068d90d34c048b
parent 9988c4ad1258af32328b6421b78794d5c29fcb35
Author: Demonstrandum <moi@knutsen.co>
Date: Sun, 8 Mar 2020 17:50:21 +0000
Added Oxford English Dictionary command interface.
Diffstat:
8 files changed, 151 insertions(+), 33 deletions(-)
diff --git a/HELP.md b/HELP.md
@@ -38,6 +38,7 @@
- `!urban [slang]` — Looks up a piece of slang in the _Urban Dictionary_.
- `!search [web-search-terms]` — Performs a web-search and returns the most appropriate URL found.
- `!image [image-search-terms]` — Searches for images specified by the terms given, and send a link to the most relevant one.
+- `!news [news-search-term]` — Sends you the most relevant new on the specified topic area.
- `!youtube [youtube-search-terms]` — Searches for and returns a relevant _YouTube_ video.
- `!cron` — Run commands repeatedly based on some timer (Google cron syntax for more info):
- `!cron [minute] [hour] [day-of-month] [month] [day-of-week] ![command] <...>` — runs a command (with or without arguments) repeatedly as specified by the schedule signature.
diff --git a/lib/api/oxford.ts b/lib/api/oxford.ts
@@ -0,0 +1,29 @@
+import unirest from 'unirest';
+
+type Options = {
+ word : string,
+ lang : string,
+ id : string,
+ key : string
+}
+
+export const oed_lookup = (options : Options) => new Promise((resolve, reject) => {
+ console.log('Searching Oxford English Dictionary, with options: ', options);
+
+ const url = 'https://od-api.oxforddictionaries.com:443/api/v2/entries';
+
+ const word = options.word.toLowerCase();
+ const req = unirest('GET', `${url}/${options.lang}/${word}`);
+
+ req.headers({
+ "app_id": options.id,
+ "app_key": options.key
+ });
+
+ req.end(res => {
+ if (res.error) return reject(res.error);
+ return resolve(res.body);
+ });
+});
+
+export default oed_lookup;
diff --git a/lib/api/urban.ts b/lib/api/urban.ts
@@ -1,6 +1,11 @@
import unirest from 'unirest';
-export const urban_search = options => new Promise((resolve, reject) => {
+type Options = {
+ query : string,
+ key : string
+}
+
+export const urban_search = (options : Options) => new Promise((resolve, reject) => {
console.log('Searching Urban Dictionary, with options: ', options);
const url = 'https://mashape-community-urban-dictionary.p.rapidapi.com/define';
diff --git a/lib/api/web.ts b/lib/api/web.ts
@@ -1,23 +1,18 @@
import unirest from 'unirest';
-export const web_search = options => new Promise((resolve, reject) => {
+type Options = {
+ query : string,
+ type : 'image' | 'web' | 'news',
+ key : string
+}
+
+export const web_search = (options : Options) => new Promise((resolve, reject) => {
console.log('Searching the web, with options: ', options);
- let api = 'WebSearchAPI';
- switch (options.type) {
- case 'image':
- api = 'ImageSearchAPI';
- break;
- case 'web':
- api = 'WebSearchAPI';
- break;
- case 'news':
- api = 'NewsSearchAPI';
- break;
- }
- const url = `https://contextualwebsearch-websearch-v1.p.rapidapi.com/api/Search/${api}`;
-
- const req = unirest('GET', url);
+ const api = `${options.type.capitalize()}SearchAPI`;
+ const url = 'https://contextualwebsearch-websearch-v1.p.rapidapi.com/api/Search';
+
+ const req = unirest('GET', `${url}/${api}`);
req.query({
"autoCorrect": "false",
diff --git a/lib/default.ts b/lib/default.ts
@@ -6,6 +6,7 @@ export default {
name: "Simp'O'Matic",
tag: "#1634",
permissions: 8,
+ lang: 'en',
commands: {
prefix: '!',
@@ -18,7 +19,9 @@ export default {
'yt': 'youtube',
'd': 'define',
'oed': 'define',
+ 'oxford': 'define',
'ud': 'urban',
+ 'u': 'urban',
'blacklist': 'ignore',
'whitelist': 'ignore whitelist',
'w': 'weather',
diff --git a/lib/extensions.ts b/lib/extensions.ts
@@ -26,12 +26,16 @@ Array.prototype.mut_map = function (f) {
// String Extensions:
interface String {
squeeze() : string
+ capitalize() : string
}
String.prototype.squeeze = function () {
return this.split(/[ ]+/).join(' ');
};
+String.prototype.capitalize = function () {
+ return this.charAt(0).toUpperCase() + this.slice(1);
+}
// Number Extensions:
interface Number {
diff --git a/lib/main.ts b/lib/main.ts
@@ -12,6 +12,7 @@ import './extensions';
import { deep_merge, pp, compile_match, export_config } from './utils';
import DEFAULT_CONFIG from './default';
import web_search from './api/web';
+import oed_lookup from './api/oxford';
import urban_search from './api/urban';
// Anything that hasn't been defined in `bot.json`
@@ -80,7 +81,7 @@ export class SimpOMatic {
console.log('Received command: ', [command, args]);
switch (command) {
- case "ping": {
+ case 'ping': {
message.reply("PONGGERS!");
break;
} case 'help': {
@@ -88,18 +89,18 @@ export class SimpOMatic {
for (const msg of HELP_MESSAGES)
message.channel.send(msg);
break;
- } case "id": {
+ } case 'id': {
const reply = `User ID: ${message.author.id}
Author: ${message.author}
Message ID: ${message.id}`.squeeze();
console.log(`Replied: ${reply}`);
message.reply(reply);
break;
- } case "search": {
+ } case 'search': {
const query = args.join(' ');
web_search({
- type: "search",
+ type: 'web',
query,
key: SECRETS.rapid.key
}).then((res: object) => {
@@ -107,14 +108,15 @@ export class SimpOMatic {
message.reply('No such results found.');
return;
}
- message.reply(`Web search for ‘${query}’, found: ${res['value'][0].url}`);
+ message.reply(`Web search for ‘${query}’,
+ found: ${res['value'][0].url}`);
}).catch(e => message.reply(`Error fetching results:\n${e}`));
break;
- } case "image": {
+ } case 'image': {
const query = args.join(' ');
web_search({
- type: "image",
+ type: 'image',
query,
key: SECRETS.rapid.key
}).then(res => {
@@ -122,34 +124,113 @@ export class SimpOMatic {
message.reply('No such images found.');
return;
}
- message.reply(`Image found for ‘${query}’: ${res['value'][0].url}`);
+ message.reply(`Image found for ‘${query}’:
+ ${res['value'][0].url}`);
}).catch(e =>
message.reply(`Error fetching image:\n${e}`));
break;
- } case "urban": {
+ } case 'define': {
+ message.reply('Looking in the Oxford English Dictionary...');
const query = args.join(' ');
+
+ const nasty_reply = `Your word (‘${query}’) is nonsense, either \
+ that or they've forgotten to index it.
+ I'll let you decide.`.squeeze();
+
+ oed_lookup({
+ word: query,
+ lang: CONFIG.lang,
+ id: SECRETS.oxford.id,
+ key: SECRETS.oxford.key
+ }).then(res => {
+ let msg = `Definition for ‘${query}’, yielded:\n`;
+
+ if (!res['results']
+ || res['results'].length == 0
+ || !res['results'][0].lexicalEntries
+ || res['results'][0].lexicalEntries.length == 0
+ || res['results'][0].lexicalEntries[0].entries.length == 0
+ || res['results'][0].lexicalEntries[0].entries[0].senses.length == 0) {
+ message.reply(nasty_reply);
+ return;
+ }
+
+ const entry = res['results'][0].lexicalEntries[0];
+ const senses = entry.entries[0].senses;
+ console.log('Senses:', pp(senses));
+ for (const sense of Object.values(senses) as any) {
+ let sense_msg = "";
+ if (!!sense.definitions && sense.definitions.length > 0) {
+ for (const definition
+ of Object.values(sense.definitions) as any) {
+ sense_msg += ` Defined as:\n> ${definition.capitalize()}\n`;
+ }
+ }
+ if (!!sense.synonyms && sense.synonyms.length > 0) {
+ const synonyms = sense.synonyms
+ .map(s => `‘${s.text}’`)
+ .join(', ');
+ sense_msg += ` Synonyms include: ${synonyms}\n`;
+ }
+ if (sense_msg.length > 0) {
+ msg += "In the sense:\n"
+ msg += sense_msg;
+ }
+ }
+ const prons = Object.values(entry.pronunciations) as any;
+ if (prons.length > 0) {
+ msg += "Pronunciations:\n"
+ for (const pron of prons) {
+ msg += ` Dialects of ${pron.dialects.join(', ')}:\n`;
+ msg += ` ${pron.phoneticNotation}: [${pron.phoneticSpelling}]\n`;
+ if (pron.audioFile) {
+ msg += ` Audio file: ${pron.audioFile}\n`;
+ const attach = new MessageAttachment(pron.audioFile);
+ attach.name = pron.audioFile.split('/').slice(-1)[0];
+ message.channel.send(attach);
+ }
+ }
+ }
+ message.channel.send(msg);
+ }).catch(e => {
+ if (e.status == 404) {
+ message.channel.send(nasty_reply);
+ } else {
+ message.channel.send(`Error getting definition:\n${e}`);
+ }
+ });
+ break;
+ } case 'urban': {
+ const query = args.join(' ');
+ message.reply('Searching Urban Dictionary...');
urban_search({ query, key: SECRETS.rapid.key }).then(res => {
if (res['list'].length === 0) {
- message.reply(`Congratulations, not even Urban \
+ message.channel.send(`Congratulations, not even Urban \
Dictionary knows what you're trying to say.`.squeeze());
return;
}
const entry = res['list'][0];
const def = entry.definition.replace(/\[|\]/g, '');
- message.reply(`Urban Dictionary defines \
- ‘${query}’, as:\n> ${def}`.squeeze());
+ message.channel.send(`**Urban Dictionary** defines \
+ ‘${query}’, as:\n>>> ${def.trim()}`.squeeze());
+
+ let example = entry.example;
+ if (!!example || example.length > 0) {
+ example = example.replace(/\[|\]/g, '');
+ message.channel.send(`\n**Example**:\n>>> ${example}`);
+ }
message.channel.send(`Link: ${entry.permalink}`);
}).catch(e => message.reply(`Error fetching definition:\n${e}`));
break;
- } case "milkies": {
+ } case 'milkies': {
message.reply(`${(4 + Math.random() * 15).round_to(3)} gallons \
of milkies have been deposited in your mouth.`.squeeze());
break;
- } case "say": {2
+ } case 'say': {2
message.reply(`Me-sa says: “${args.join(' ')}”`);
break;
- } case "export": {
+ } case 'export': {
let export_string = export_config(CONFIG, {});
if (export_string.length > 1980) {
export_string = export_config(CONFIG, { ugly: true });
diff --git a/lib/utils.ts b/lib/utils.ts
@@ -13,7 +13,7 @@ export const type: (obj: any) => string = (global => obj =>
export const pp = o => inspect(o, {
colors: true,
showHidden: false,
- depth: 8
+ depth: 50
});
export const deep_merge_pair = (target, source) => {