From 98886385b1bbe14cbf21873ab24b9ed36d61a2cc Mon Sep 17 00:00:00 2001 From: MrRGnome <5963774+MrRGnome@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:05:31 -0600 Subject: [PATCH] Add define command backed by dictionary API meanings --- commands/define.js | 74 ++++++++++++++++++++++++++++++++++++++++++ services/dictionary.js | 42 ++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 commands/define.js create mode 100644 services/dictionary.js diff --git a/commands/define.js b/commands/define.js new file mode 100644 index 0000000..a90beea --- /dev/null +++ b/commands/define.js @@ -0,0 +1,74 @@ +const { getMeanings } = require('../services/dictionary'); + +const MAX_MEANINGS = 8; +const MAX_DEFINITIONS_PER_MEANING = 3; +const MAX_MESSAGE_LENGTH = 1900; + +function summarizeMeaning(meaning) { + const definitions = meaning.definitions.slice(0, MAX_DEFINITIONS_PER_MEANING); + if (!definitions.length) + return null; + + const partOfSpeech = meaning.partOfSpeech ? `${meaning.partOfSpeech}: ` : ''; + return `${partOfSpeech}${definitions.join(' | ')}`; +} + +function buildMeaningsMessage(term, meanings) { + const summaries = meanings + .map(summarizeMeaning) + .filter(Boolean) + .slice(0, MAX_MEANINGS); + + const lines = [`Meanings for **${term}**:`]; + let added = 0; + + for (let i = 0; i < summaries.length; i++) { + const candidateLine = `${i + 1}. ${summaries[i]}`; + const preview = `${lines.join('\n')}\n${candidateLine}`; + + if (preview.length > MAX_MESSAGE_LENGTH) + break; + + lines.push(candidateLine); + added++; + } + + const hiddenCount = Math.max(0, summaries.length - added) + Math.max(0, meanings.length - MAX_MEANINGS); + if (hiddenCount > 0) + lines.push(`...and ${hiddenCount} more meaning(s).`); + + return lines.join('\n'); +} + +async function defineCommand(message, args) { + const term = args.join(' ').trim(); + + if (!term) { + await message.channel.send(`Please provide a term. Example: \`${message.client.prefix}define bitcoin\``); + return; + } + + let meanings; + try { + meanings = await getMeanings(term); + } catch { + await message.channel.send('Unable to fetch definitions right now. Please try again later.'); + return; + } + + if (meanings.length === 0) { + await message.channel.send(`No meanings found for **${term}**.`); + return; + } + + await message.channel.send(buildMeaningsMessage(term, meanings)); +} + +module.exports = { + define: { + execute: defineCommand + }, + def: { + execute: defineCommand + } +}; diff --git a/services/dictionary.js b/services/dictionary.js new file mode 100644 index 0000000..d6211d4 --- /dev/null +++ b/services/dictionary.js @@ -0,0 +1,42 @@ +const axios = require('axios'); + +const DICTIONARY_API_URL = 'https://api.dictionaryapi.dev/api/v2/entries/en/'; + +function normalizeMeaning(meaning) { + const partOfSpeech = String(meaning?.partOfSpeech || '').trim(); + const definitions = Array.isArray(meaning?.definitions) + ? meaning.definitions + .map(definition => String(definition?.definition || '').trim()) + .filter(Boolean) + : []; + + return { + partOfSpeech, + definitions + }; +} + +async function getMeanings(term) { + const normalizedTerm = String(term || '').trim(); + if (!normalizedTerm) + return []; + + try { + const response = await axios.get(`${DICTIONARY_API_URL}${encodeURIComponent(normalizedTerm)}`); + const entries = Array.isArray(response.data) ? response.data : []; + + return entries + .flatMap(entry => Array.isArray(entry?.meanings) ? entry.meanings : []) + .map(normalizeMeaning) + .filter(meaning => meaning.definitions.length > 0); + } catch (error) { + if (error.response?.status === 404) + return []; + + throw new Error('Failed to fetch meanings.'); + } +} + +module.exports = { + getMeanings +};