replace lexicala with wordnik
This commit is contained in:
parent
4f887e3331
commit
2b42fb63f4
@ -2,7 +2,7 @@
|
|||||||
"main": "plugin.js",
|
"main": "plugin.js",
|
||||||
"name": "diction",
|
"name": "diction",
|
||||||
"description": "Find definitions for words",
|
"description": "Find definitions for words",
|
||||||
"version": "1.1.0",
|
"version": "1.2.1",
|
||||||
"tags": ["commands", "utility", "dictionary"],
|
"tags": ["commands", "utility", "dictionary"],
|
||||||
"dependencies": ["simplecommands"],
|
"dependencies": ["simplecommands"],
|
||||||
"npmDependencies": []
|
"npmDependencies": []
|
||||||
|
@ -8,28 +8,60 @@ import {
|
|||||||
} from '@squeebot/core/lib/plugin';
|
} from '@squeebot/core/lib/plugin';
|
||||||
import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
|
import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
|
||||||
|
|
||||||
const poslist = [
|
interface IDefinition {
|
||||||
'noun',
|
partOfSpeech: string;
|
||||||
'verb',
|
text: string;
|
||||||
'adjective',
|
}
|
||||||
'adverb',
|
|
||||||
'participle',
|
interface IWordCache {
|
||||||
'article',
|
lastIndex: {
|
||||||
'pronoun',
|
name: string;
|
||||||
'preposition',
|
index: number;
|
||||||
'conjunction',
|
lastTime: number;
|
||||||
'interjection',
|
}[];
|
||||||
'determiner',
|
definitions: IDefinition[];
|
||||||
];
|
inserted: number;
|
||||||
|
}
|
||||||
|
|
||||||
let lastQuery = 0;
|
let lastQuery = 0;
|
||||||
|
const wordCache: Record<string, IWordCache> = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and remove words that haven't been looked up for a day
|
||||||
|
*/
|
||||||
|
function flushCache() {
|
||||||
|
let oldestWords: string[] = [];
|
||||||
|
Object.keys(wordCache).forEach((word) => {
|
||||||
|
const cached = wordCache[word];
|
||||||
|
let notOld = false;
|
||||||
|
|
||||||
|
for (const person of cached.lastIndex) {
|
||||||
|
if (person.lastTime > Date.now() - 24 * 60 * 60 * 1000) {
|
||||||
|
notOld = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notOld) {
|
||||||
|
oldestWords.push(word);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!oldestWords.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldestWords.forEach((item) => {
|
||||||
|
delete wordCache[item];
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.log(`[diction] Dictionary cleared of the previous words ${oldestWords.join(', ')}.`);
|
||||||
|
}
|
||||||
|
|
||||||
@Configurable({
|
@Configurable({
|
||||||
lexicala: {
|
wordnik: '',
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
},
|
|
||||||
cooldown: 5,
|
cooldown: 5,
|
||||||
|
limit: 5,
|
||||||
})
|
})
|
||||||
class DictionPlugin extends Plugin {
|
class DictionPlugin extends Plugin {
|
||||||
@EventListener('pluginUnload')
|
@EventListener('pluginUnload')
|
||||||
@ -41,13 +73,12 @@ class DictionPlugin extends Plugin {
|
|||||||
|
|
||||||
@DependencyLoad('simplecommands')
|
@DependencyLoad('simplecommands')
|
||||||
addCommands(cmd: any): void {
|
addCommands(cmd: any): void {
|
||||||
const user = this.config.get('lexicala.username');
|
const key = this.config.get('wordnik');
|
||||||
const passwd = this.config.get('lexicala.password');
|
|
||||||
const rate = this.config.get('cooldown', 5);
|
const rate = this.config.get('cooldown', 5);
|
||||||
const rauth = 'Basic ' + Buffer.from(`${user}:${passwd}`).toString('base64');
|
const limit = this.config.get('limit', 5);
|
||||||
|
|
||||||
if (!user || !passwd) {
|
if (!key) {
|
||||||
logger.warn('Lexicala define command is disabled due to no credentials.');
|
logger.warn('Wordnik define command is disabled due to no credentials.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,66 +86,105 @@ class DictionPlugin extends Plugin {
|
|||||||
name: 'define',
|
name: 'define',
|
||||||
plugin: this.name,
|
plugin: this.name,
|
||||||
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
|
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
|
||||||
if (lastQuery > Date.now() - rate * 1000) {
|
const word = simplified.join(' ');
|
||||||
msg.resolve('You\'re doing that too fast!');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pos: string | null = simplified[0];
|
|
||||||
if (pos && poslist.indexOf(pos.toLowerCase()) !== -1 && simplified.length > 1) {
|
|
||||||
pos = '&pos=' + pos;
|
|
||||||
} else {
|
|
||||||
pos = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const word = encodeURIComponent(simplified.slice(pos ? 1 : 0).join(' '));
|
|
||||||
|
|
||||||
if (!word) {
|
if (!word) {
|
||||||
msg.resolve('Please specifiy a word or term!');
|
msg.resolve('Please specifiy a word or term!');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastQuery = Date.now();
|
if (lastQuery > Date.now() - rate * 1000 && !wordCache[word]) {
|
||||||
|
msg.resolve('You\'re doing that too fast!');
|
||||||
let response;
|
|
||||||
try {
|
|
||||||
const s = `https://dictapi.lexicala.com/search?source=global&language=en${pos}&text=${word}`;
|
|
||||||
response = await httpGET(s, { Authorization: rauth });
|
|
||||||
response = JSON.parse(response);
|
|
||||||
} catch (e) {
|
|
||||||
msg.resolve('Server did not respond.');
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.n_results || response.n_results === 0 || !response.results) {
|
let chosenDefinition: IDefinition;
|
||||||
msg.resolve('Nothing found.');
|
let definitionCount = 0;
|
||||||
return true;
|
let definitionIndex = 0;
|
||||||
|
|
||||||
|
// Check cached definitions
|
||||||
|
const userTarget = msg.fullSenderID as string;
|
||||||
|
if (wordCache[word]) {
|
||||||
|
const cached = wordCache[word];
|
||||||
|
const alreadyAsked = cached.lastIndex.find((item) => item.name === userTarget);
|
||||||
|
definitionCount = cached.definitions.length;
|
||||||
|
|
||||||
|
if (alreadyAsked) {
|
||||||
|
let nextI = alreadyAsked.index + 1;
|
||||||
|
|
||||||
|
if (nextI >= cached.definitions.length) {
|
||||||
|
nextI = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alreadyAsked.lastTime < Date.now() - 5 * 60 * 1000) {
|
||||||
|
nextI = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
alreadyAsked.lastTime = Date.now();
|
||||||
|
alreadyAsked.index = nextI;
|
||||||
|
definitionIndex = nextI;
|
||||||
|
chosenDefinition = cached.definitions[nextI];
|
||||||
|
} else {
|
||||||
|
chosenDefinition = cached.definitions[0];
|
||||||
|
cached.lastIndex.push({
|
||||||
|
name: userTarget,
|
||||||
|
index: 0,
|
||||||
|
lastTime: Date.now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Request definition
|
||||||
|
const encodedWord = encodeURIComponent(word);
|
||||||
|
lastQuery = Date.now();
|
||||||
|
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
const s = `https://api.wordnik.com/v4/word.json/${encodedWord}/definitions?limit=${limit}&api_key=${key}`;
|
||||||
|
response = await httpGET(s);
|
||||||
|
response = JSON.parse(response);
|
||||||
|
} catch (e) {
|
||||||
|
msg.resolve('Server did not respond.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response || !response.length) {
|
||||||
|
msg.resolve('No definitions found.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cached: IWordCache = {
|
||||||
|
lastIndex: [
|
||||||
|
{
|
||||||
|
name: userTarget,
|
||||||
|
index: 0,
|
||||||
|
lastTime: Date.now(),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
definitions: (response as Record<string, string>[]).map(({ partOfSpeech, text }) => ({
|
||||||
|
partOfSpeech, text: text.replace(/(<([^>]+)>)/ig, '')
|
||||||
|
})),
|
||||||
|
inserted: Date.now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
wordCache[word] = cached;
|
||||||
|
chosenDefinition = cached.definitions[0];
|
||||||
|
definitionCount = cached.definitions.length;
|
||||||
|
logger.log(`[diction] Dictionary cached the word "${word}"`);
|
||||||
|
flushCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolve = [];
|
const { partOfSpeech, text } = chosenDefinition;
|
||||||
for (const def of response.results) {
|
|
||||||
const wd = def.headword.text;
|
|
||||||
const wdp = def.headword.pos;
|
|
||||||
const results = def.senses.map((rep: any) => rep.definition).slice(0, 4);
|
|
||||||
|
|
||||||
resolve.push({
|
msg.resolve(`(${definitionIndex + 1}/${definitionCount}) ${word}${
|
||||||
word: wd,
|
partOfSpeech ? ` - ${partOfSpeech}` : ''
|
||||||
type: wdp,
|
} - ${text}`);
|
||||||
results,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const str = resolve.slice(0, 4).map((rep: any) => {
|
|
||||||
return `${rep.word} (${rep.type}):\n` + rep.results.join('\n');
|
|
||||||
}).join('\n');
|
|
||||||
|
|
||||||
msg.resolve(str);
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
match: /define (\w*)/,
|
match: /define (\w*)/,
|
||||||
aliases: ['df'],
|
aliases: ['df'],
|
||||||
description: 'Find definitions for words',
|
description: 'Find definitions for words. Call again to advance to next definition',
|
||||||
usage: '[<pos>] <word>'
|
usage: '<word>'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "diction",
|
"name": "diction",
|
||||||
"version": "1.1.0"
|
"version": "1.2.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fun",
|
"name": "fun",
|
||||||
|
Loading…
Reference in New Issue
Block a user