/* eslint-disable comma-dangle */ // dotenv for handling environment variables const dotenv = require('dotenv'); dotenv.config(); // Assignment of environment variables for database access const dbHost = process.env.dbHost; const dbUser = process.env.dbUser; const dbName = process.env.dbName; const dbPass = process.env.dbPass; const dbPort = process.env.dbPort; const isDev = process.env.isDev; const ownerId = process.env.ownerId; // filesystem const fs = require('fs'); const zlib = require('zlib'); // Discord.js const Discord = require('discord.js'); // Fuzzy text matching for db lookups const FuzzySearch = require('fuzzy-search'); // OpenAI // const OpenAI = require("openai"); // const openai = new OpenAI(); // Axios for APIs const axios = require('axios'); // Various imports from other files const config = require('./config.json'); const strings = require('./strings.json'); const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js')); // MySQL database connection const mysql = require('mysql'); const { GifData, PastaData } = require('./CustomModules/NodBot'); const db = new mysql.createPool({ connectionLimit: 10, host: dbHost, user: dbUser, password: dbPass, database: dbName, port: dbPort, }); const functions = { // Functions for managing and creating Collections collections: { // Create the collection of slash commands slashCommands(client) { if (!client.slashCommands) client.slashCommands = new Discord.Collection(); client.slashCommands.clear(); for (const file of slashCommandFiles) { const slashCommand = require(`./slash-commands/${file}`); if (slashCommand.data != undefined) { client.slashCommands.set(slashCommand.data.name, slashCommand); } } if (isDev) console.log('Slash Commands Collection Built'); }, setvalidCommands(client) { for (const entry of client.dotCommands.map(command => command)) { config.validCommands.push(entry.name); if (Array.isArray(entry.alias)) { entry.alias.forEach(element => { config.validCommands.push(element); }); } else if (entry.alias != undefined) { config.validCommands.push(entry.alias); } } if (isDev) console.log(`Valid Commands Added to Config\n${config.validCommands}`); }, dotCommands(client) { if (!client.dotCommands) client.dotCommands = new Discord.Collection(); client.dotCommands.clear(); for (const file of dotCommandFiles) { const dotCommand = require(`./dot-commands/${file}`); client.dotCommands.set(dotCommand.name, dotCommand); if (Array.isArray(dotCommand.alias)) { dotCommand.alias.forEach(element => { client.dotCommands.set(element, dotCommand); }); } else if (dotCommand.alias != undefined) { client.dotCommands.set(dotCommand.alias, dotCommand); } } if (isDev) console.log('Dot Commands Collection Built'); }, gifs(rows, client) { if (!client.gifs) client.gifs = new Discord.Collection(); client.gifs.clear(); for (const row of rows) { // const gif = { // id: row.id, // name: row.name, // embed_url: row.embed_url // }; const gifData = new GifData().setInfo(row.name, row.embed_url); client.gifs.set(gifData.name, gifData); } if (isDev) console.log('GIFs Collection Built'); }, joints(rows, client) { if (!client.joints) client.joints = new Discord.Collection(); client.joints.clear(); for (const row of rows) { const joint = { id: row.id, content: row.content }; client.joints.set(joint.id, joint); } if (isDev) console.log('Joints Collection Built'); }, pastas(rows, client) { if (!client.pastas) client.pastas = new Discord.Collection(); client.pastas.clear(); for (const row of rows) { const pastaData = new PastaData().setInfo(row.name, row.content, row.iconurl, row.id); client.pastas.set(pastaData.name, pastaData); } if (isDev) console.log('Pastas Collection Built'); }, requests(rows, client) { if (!client.requests) client.requests = new Discord.Collection(); client.requests.clear(); for (const row of rows) { const request = { id: row.id, author: row.author, request: row.request, }; client.requests.set(request.id, request); } if (isDev) console.log('Requests Collection Built'); }, strains(rows, client) { if (!client.strains) client.strains = new Discord.Collection(); client.strains.clear(); for (const row of rows) { const strain = { id: row.id, name: row.strain, }; client.strains.set(strain.name, strain); // if (isDev) console.log(strain) } if (isDev) console.log('Strains Collection Built'); }, medicalAdvice(rows, client) { if (!client.medicalAdviceColl) client.medicalAdviceColl = new Discord.Collection(); client.medicalAdviceColl.clear(); for (const row of rows) { const medicalAdvice = { id: row.id, content: row.content }; client.medicalAdviceColl.set(medicalAdvice.id, medicalAdvice); } if (isDev) console.log('Medical Advice Collection Built'); }, roaches(client) { if (!client.roaches) client.roaches = new Discord.Collection(); client.roaches.clear(); if (isDev) console.log('Medical Advice Collection Built'); } }, dot: { getCommandData(message) { const commandData = {}; // Split the message content at the final instance of a period const finalPeriod = message.content.lastIndexOf('.'); // if(isDev) console.log(message.content); // If the final period is the last character, or doesn't exist if (finalPeriod < 0) { if (isDev) console.log(finalPeriod); commandData.isCommand = false; return commandData; } commandData.isCommand = true; // Get the first part of the message, everything leading up to the final period commandData.args = message.content.slice(0,finalPeriod).toLowerCase(); // Get the last part of the message, everything after the final period commandData.command = message.content.slice(finalPeriod + 1).toLowerCase(); commandData.author = `${message.author.username}`; return this.checkCommand(commandData); }, checkCommand(commandData) { if (commandData.isCommand) { const validCommands = require('./config.json').validCommands; commandData.isValid = validCommands.includes(commandData.command); // Add exceptions for messages that contain only a link if (commandData.args.startsWith('http')) commandData.isValid = false; } else { commandData.isValid = false; console.error('Somehow a non-command made it to checkCommands()'); } return commandData; } }, embeds: { help(interaction) { // Construct the Help Embed const helpEmbed = new Discord.MessageEmbed() .setColor('BLUE') .setAuthor({name: 'Help Page'}) .setDescription(strings.help.description) .setThumbnail(strings.urls.avatar); // Construct the Slash Commands help let slashCommandsFields = []; const slashCommandsMap = interaction.client.slashCommands.map(e => { return { name: e.data.name, description: e.data.description }; }) for (const e of slashCommandsMap) { slashCommandsFields.push({ name: `- /${e.name}`, value: e.description, inline: false, }); } // Construct the Dot Commands Help let dotCommandsFields = []; const dotCommandsMap = interaction.client.dotCommands.map(e => { return { name: e.name, description: e.description, usage: e.usage }; }); for (const e of dotCommandsMap) { dotCommandsFields.push({ name: `- .${e.name}`, value: `${e.description}\nUsage: ${e.usage}`, inline: false, }); } helpEmbed.addField('Slash Commands', strings.help.slash); helpEmbed.addFields(slashCommandsFields); helpEmbed.addField('Dot Commands', strings.help.dot); helpEmbed.addFields(dotCommandsFields); return { embeds: [ helpEmbed ], ephemeral: true }; }, gif(commandData) { return { embeds: [new Discord.MessageEmbed() .setAuthor({name: `${commandData.args}.${commandData.command}`}) .setImage(commandData.embed_url) .setTimestamp() .setFooter({text: commandData.author})]}; }, pasta(commandData, pastaData) { return { embeds: [ new Discord.MessageEmbed() .setAuthor({name: `${commandData.args}.${commandData.command}`}) .setDescription(pastaData.content) .setThumbnail("https://assets.vfsh.dev/shednod.png") .setTimestamp() .setFooter({text: commandData.author})]}; }, pastas(commandData) { const pastasArray = []; const pastasEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() .setFooter({text: commandData.author}); for (const row of commandData.pastas) { pastasArray.push(`#${row.id} - ${row.name}.pasta`); } const pastasString = pastasArray.join('\n'); pastasEmbed.setDescription(pastasString); return { embeds: [pastasEmbed], ephemeral: true }; }, gifs(commandData, gifList) { const gifsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() .setFooter({text: commandData.author}) .setDescription(gifList.join('\n')); return { embeds: [gifsEmbed] }; }, text(commandData) { return { embeds: [new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setDescription(commandData.content) .setTimestamp() .setFooter({text: commandData.author})]}; }, requests(commandData) { const requestsEmbed = new Discord.MessageEmbed() .setAuthor({name: commandData.command}) .setTimestamp() .setFooter({text: commandData.author}); const requestsArray = []; for (const row of commandData.requests) { requestsArray.push( `**#${row.id} - ${row.author}**`, `Request: ${row.request}` ); } requestsEmbed.setDescription(requestsArray.join('\n')); return { embeds: [requestsEmbed], ephemeral: true }; }, strain(strainInfo, interaction) { const strainEmbed = new Discord.MessageEmbed() .setTimestamp(); strainEmbed.addFields([ { name: 'Strain Name', value: `${strainInfo.strain}`, inline: true, }, { name: 'Type', value: `${strainInfo.type}`, inline: true, }, { name: 'Effects', value: `${strainInfo.effects}`, inline: true, }, { name: 'Flavor', value: `${strainInfo.flavor}`, inline: true, }, { name: 'Rating', value: `⭐️${strainInfo.rating}`, inline: true, }, { name: 'Description', value: `${strainInfo.description}`, inline: false, }, ]); interaction.reply({ embeds: [ strainEmbed ]}); }, dalle(prompt, imageUrl, size) { const dalleEmbed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by DALL-E", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) .addFields( { name: "Prompt", value: prompt } ) .setImage(imageUrl) .setFooter({ text: `This ${size} image cost ${strings.costs.dalle[size]}¢ to generate.` }) return { embeds: [dalleEmbed] }; }, gpt(prompt, response, usage) { const gptEmbed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by GPT-3.5", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) .setDescription(`**Prompt**\n${prompt}\n\n**Response**\n${response}`) .setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usdc}¢. Generated using ${strings.ai.chatModel}` }) return { embeds: [gptEmbed] }; }, generatingResponse() { const embed = new Discord.MessageEmbed() .setAuthor({ name: "NodBot powered by OpenAI", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" }) .setImage("https://media.tenor.com/aHMHzNGCb4kAAAAC/sucks.gif") .setDescription("Generating a response, please stand by.") .setFooter({ text: "Ligma balls" }); return { embeds: [embed] }; }, avWx: { metar(metarData) { const wgst = metarData.wgst ? `G${metarData.wgst}` : ''; const clouds = []; const interAltim = Math.round((metarData.altim * 0.2952998057228486) * 10) const altim = interAltim / 100; metarData.clouds.forEach(cloudLayer => { if (cloudLayer.base !== null) { clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}'`); } else { clouds.push(`${cloudLayer.cover}`); } }); const embed = new Discord.MessageEmbed() .setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"}) // .setImage("https://media.discordapp.net/stickers/1175134632845516821.webp") .setDescription(`**Not for real world use!**\n\n${metarData.rawOb}`) .setFooter({ text: "METAR by AviationWeather.gov for CumbHub LLC" }) .addFields( { name: 'Observation Time', value: `${metarData.reportTime}Z` }, { name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`}, { name: 'Winds', value: `${metarData.wdir.toString().padStart(3, '0')}º@${metarData.wspd}${wgst} kts`}, { name: 'Visibility', value: `${metarData.visib} SM` }, { name: 'Clouds', value: clouds.join('\n') }, { name: 'Altimeter', value: `${altim} inHg` } ) return { embeds: [embed] }; }, datis(datisData) { const messageEmbed = new Discord.MessageEmbed() .setAuthor({ name: `${datisData[0].airport} Digital ATIS` }) // .setImage('https://media.discordapp.net/stickers/1175134632845516821.webp') .setDescription(`**Do not use for real world flight planning or navigation.**`) .setFooter({ text: 'D-ATIS by Clowd.io for CumbHub LLC' }) if (datisData.length > 1) { datisData.forEach(data => { if (data.type === 'dep') messageEmbed.addFields({ name: 'Departure Digital ATIS', value: data.datis, inline: false }); if (data.type === 'arr') messageEmbed.addFields({ name: 'Arrival Digital ATIS', value: data.datis, inline: false }); messageEmbed.addFields({ name: 'Information', value: data.code, inline: true }); }) messageEmbed.addFields( { name: 'Retreival Time', value: `${new Date().toISOString()}` } ); } else { messageEmbed.addFields( { name: 'Digital ATIS', value: datisData[0].datis, inline: false }, { name: 'Information', value: `${datisData[0].code}`, inline: true }, { name: 'Retreival Time', value: `${new Date().toISOString()}`, inline: true } ) } const messagePayload = { embeds: [ messageEmbed ] }; return messagePayload; } } }, collect: { gifName(interaction) { const gifNameFilter = m => m.author.id == strings.temp.gifUserId; return interaction.channel.createMessageCollector({ filter: gifNameFilter, time: 30000 }); }, }, upload: { request(commandData, client) { const query = `INSERT INTO requests (author, request, status) VALUES (${db.escape(commandData.author)},${db.escape(commandData.args)},'Active')`; db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.requests(client); }); }, async pasta(pastaData, client) { const query = `INSERT INTO pastas (name, content) VALUES (${db.escape(pastaData.name)},${db.escape(pastaData.content)}) ON DUPLICATE KEY UPDATE content=${db.escape(pastaData.content)}`; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.pastas(client); }); return; }, joint(content, client) { const query = `INSERT INTO joints (content) VALUES (${db.escape(content)})`; db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.joints(client); }); }, async gif(gifData, client) { const query = `INSERT INTO gifs (name, embed_url) VALUES (${db.escape(gifData.name)}, ${db.escape(gifData.url)}) ON DUPLICATE KEY UPDATE embed_url=${db.escape(gifData.url)}`; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.gifs(client); }); }, setup(interaction) { /* Tables: * - gifs * - joints * - pastas * - requests * - strains */ const gifsQuery = "CREATE TABLE 'gifs' (id int(11), name varchar(100), embed_url varchar(1000), PRIMARY KEY(id))"; const jointsQuery = "CREATE TABLE 'joints' (id int(11), content varchar(1000), PRIMARY KEY(id))"; const pastasQuery = "CREATE TABLE 'pastas' (id int(11), name varchar(100), content varchar(1900), iconurl varchar(200) DEFAULT 'https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128', PRIMARY KEY(id))"; const requestsQuery = "CREATE TABLE 'requests' (id int(11), author varchar(100), request varchar(1000), status varchar(10) DEFAULT 'Active', PRIMARY KEY(id))"; const strainsQuery = "CREATE TABLE 'strains' (id smallint(6), name varchar(60), type varchar(10), effects varchat(80), ailment varchar(70), flavor varchar(30), PRIMARY KEY(id))"; // Check for owner if (interaction.user.id == ownerId) { db.query(gifsQuery, (err, rows, fields) => { if (err) throw err; }); db.query(jointsQuery, (err, rows, fields) => { if (err) throw err; }); db.query(pastasQuery, (err, rows, fields) => { if (err) throw err; }); db.query(requestsQuery, (err, rows, fields) => { if (err) throw err; }); db.query(strainsQuery, (err, rows, fields) => { if (err) throw err; }); return 'I\'ve created the required tables. Please check your database to validate this.'; } else { return 'Sorry, you don\'t have permission to do that.'; } }, medicalAdvice(content, client) { const query = `INSERT INTO medical_advice (content) VALUES (${db.escape(content)})`; db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.medicalAdvice(client); }); }, strain(interaction) { const strain = db.escape(interaction.options.getString('name')); const type = db.escape(interaction.options.getString('type')); const effects = db.escape(( interaction.options.getString('effects') || 'Unkown' )); const description = db.escape(( interaction.options.getString('description') || 'Unknown' )); const flavor = db.escape(( interaction.options.getString('flavor') || 'Unknown' )); const rating = db.escape(( interaction.options.getString('rating') || '3' )); const strainQuery = `INSERT INTO strains (strain, type, effects, description, flavor, rating) VALUES (${strain}, ${type}, ${effects}, ${description}, ${flavor}, ${rating}) ON DUPLICATE KEY UPDATE strain=${db.escape(strain)}, type=${db.escape(type)}, effects=${db.escape(effects)}, description=${db.escape(description)}, flavor=${db.escape(flavor)}, rating=${db.escape(rating)}`; console.log(strainQuery); return new Promise((resolve, reject) => { db.query(strainQuery, (err, rows, fields) => { if (err) reject(err); functions.download.strains(interaction.client); resolve(); }); }) }, openai(user, prompt, engine, tokens, usdc) { const query = `INSERT INTO openai (user, prompt, engine, tokens, usdc) VALUES (${db.escape(user)}, ${db.escape(prompt)}, ${db.escape(engine)}, ${db.escape(tokens)}, ${db.escape(usdc)})`; db.query(query, (err) => { if (err) throw err; }); } }, download: { async requests(client) { const query = 'SELECT * FROM requests WHERE status = \'Active\' ORDER BY id DESC'; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.requests(rows, client); }); }, async pastas(client) { const query = 'SELECT * FROM pastas ORDER BY id ASC'; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.pastas(rows, client); }); }, async gifs(client) { const query = 'SELECT * FROM gifs ORDER BY id ASC'; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.gifs(rows, client); }); }, async joints(client) { const query = 'SELECT * FROM joints ORDER BY id ASC'; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.joints(rows, client); }); }, async strain(strainName, interaction) { const query = `SELECT id, strain, type, effects, description, flavor, rating FROM strains WHERE strain = ${db.escape(strainName)}`; await db.query(query, (err, rows, fields) => { if (rows != undefined) { const strainInfo = { id: `${rows[0].id}`, strain: `${rows[0].strain}`, type: `${rows[0].type}`, effects: `${rows[0].effects}`, description: `${rows[0].description}`, flavor: `${rows[0].flavor}`, rating: `${rows[0].rating}`, }; functions.embeds.strain(strainInfo, interaction); } }); }, async strains(client) { const query = 'SELECT id, strain FROM strains'; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.strains(rows, client); }); }, async medicalAdvice(client) { const query = 'SELECT * FROM medical_advice ORDER BY id ASC'; await db.query(query, (err, rows, fields) => { if (err) throw err; functions.collections.medicalAdvice(rows, client); }); } }, weed: { strain: { lookup(strainName, client) { const strainSearcher = new FuzzySearch(client.strains.map(e => e.name)); return strainSearcher.search(strainName).slice(0,25); }, submit(strainName) { const query = `` return strainName; } } }, openAI: { chatPrompt(userPrompt) { return new Promise(async (resolve, reject) => { const response = await openai.chat.completions.create({ messages: [{ role: 'user', content: userPrompt }], model: strings.ai.chatModel }).catch(e => { reject(e); return null; }); resolve(response); }); }, imagePrompt(userPrompt, size, userId) { return new Promise(async (resolve, reject) => { try { const response = await openai.createImage({ prompt: userPrompt, size: size, user: userId }); resolve(response.data.data[0].url); } catch (e) { reject(e); return; } }); } }, search: { gifs(query, client) { const gifSearcher = new FuzzySearch(client.gifs.map(element => element.name)); return gifSearcher.search(query).slice(0,25); }, pastas(query, client) { const pastaSearcher = new FuzzySearch(client.pastas.map(element => element.name)); return pastaSearcher.search(query).slice(0,25); } }, // Parent-Level functions (miscellaneuous) closeRequest(requestId, interaction) { if (interaction.user.id == ownerId) { const { client } = interaction; const query = `UPDATE requests SET status = 'Closed' WHERE id = ${db.escape(requestId)}`; db.query(query, (err, rows, fields) => { if (err) throw err; functions.download.requests(client); }); interaction.reply({ content: `Request #${requestId} has been closed.`, ephemeral: true }); } else { interaction.reply({ content: 'You do not have permission to do that.', ephemeral: true }); } if (isDev) { console.log(requestId, interaction, ownerId); } }, spongebob(commandData) { let newText = ''; let lastIsUpper = 0; for (const letter of commandData.args) { if (letter == ' ') { newText += letter; continue; } if (letter == 'i' || letter == 'I') { newText += 'i'; lastIsUpper = 0; continue; } if (letter == 'l' || letter == 'L') { newText += 'L'; lastIsUpper = 1; continue; } if (lastIsUpper === 0) { newText += letter.toUpperCase(); lastIsUpper = 1; } else { newText += letter.toLowerCase(); lastIsUpper = 0; } } return newText + ' <:spongebob:1053398825965985822>'; }, autoresponses: { // Specific responses for certain keywords in sent messages checkForAll(messageContent) { let responses = []; if (this.bigDoinks(messageContent)) responses.push("bigDoinks"); if (this.ligma(messageContent)) responses.push("ligma"); if (this.ong(messageContent)) responses.push("ong"); if (this.fuckYou(messageContent)) responses.push("fuckYou"); return responses; }, bigDoinks(messageContent) { let count = 0; const { keywords } = strings.autoresponses.bigDoinks; keywords.forEach(e => { if (messageContent.includes(e)) count++; }); if (count === keywords.length) { return true; } }, ligma(messageContent) { let count = 0; const { keywords } = strings.autoresponses.ligma; keywords.forEach(e => { if (messageContent.includes(e)) count++; }); if (count > 0) { return true; } }, ong(messageContent) { let count = 0; const { keywords } = strings.autoresponses.ong; keywords.forEach(e => { if (messageContent.includes(e)) count++; }); if (count > 0) { return true; } }, fuckYou(messageContent) { let count = 0; const { keywords } = strings.autoresponses.fuckYou; keywords.forEach(e => { if (messageContent.includes(e)) count++; }); if (count === keywords.length) { return true; } }, send(message, responseType) { const { responses } = strings.autoresponses[responseType]; const randomIndex = Math.floor(Math.random() * responses.length); const response = responses[randomIndex]; try { message.reply(response); } catch(e) { console.log(new Error(e)); } } }, avWx: { parseICAOs(commandData) { let input = commandData.args.toUpperCase(); // Replace newlines and different delimiters with a comma let standardizedInput = input.replace(/[\s,;]+/g, ','); // Split the string by commas let icaoArray = standardizedInput.split(','); // Trim each element to remove extra whitespace icaoArray = icaoArray.map(icao => icao.trim()).filter(icao => icao.length > 0); icaoArray.forEach(icao => { if (!(config.icaoIds.includes(icao))) throw new Error(`Invalid ICAO ID Detected: ${icao}`); }); // Join the array into a comma-separated string return icaoArray.join(','); }, metar: { async getAllICAOs() { const reqUrl = `https://aviationweather.gov/data/cache/stations.cache.json.gz` try { // Step 1: Download the GZipped file const response = await axios({ url: reqUrl, method: 'GET', responseType: 'arraybuffer', // Ensure we get the raw binary data headers: { 'Accept-Encoding': 'gzip' // Ensure the server sends gzipped content } }); // Step 2: Decompress the GZipped content const buffer = Buffer.from(response.data); zlib.gunzip(buffer, (err, decompressedBuffer) => { if (err) { console.error('An error occurred during decompression:', err); return; } // Step 3: Parse the decompressed JSON const jsonString = decompressedBuffer.toString('utf-8'); try { const jsonData = JSON.parse(jsonString); // console.log('Parsed JSON data:', jsonData); jsonData.forEach(airport => { config.icaoIds.push(airport.icaoId); }); // console.log(`ICAO IDs: ${config.icaoIds.length}\n\n${config.icaoIds}`) } catch (jsonError) { console.error('An error occurred while parsing JSON:', jsonError); } }); } catch (error) { console.error('An error occurred during the HTTP request:', error); } }, async getData(icaoList) { const reqUrl = `https://aviationweather.gov/api/data/metar?ids=${icaoList}&format=json`; const response = await axios.get(reqUrl); return response.data; }, parseData(metarData) { let messages = []; metarData.forEach(metar => { messages.push(functions.embeds.avWx.metar(metar)); }) return messages; } }, datis: { async getAllICAOs() { const reqUrl = 'https://datis.clowd.io/api/stations'; const response = await axios.get(reqUrl); response.data.forEach(icaoId => { config.datisICAOs.push(icaoId); }); }, validate(icaoId) { return config.datisICAOs.includes(icaoId); }, async getData(icaoId) { const reqUrl = `https://datis.clowd.io/api/${icaoId}`; const response = await axios.get(reqUrl); if (response.error !== undefined) throw new Error('The D-ATIS API returned an error:\n' + response.error); return response.data; }, parseData(datisData) { return functions.embeds.avWx.datis(datisData); } } }, generateErrorId() { const digitCount = 10; const digits = []; for (let i = 0; i < digitCount; i++) { const randBase = Math.random(); const randNumRaw = randBase * 10; const randNumRound = Math.floor(randNumRaw); digits.push(randNumRound); } const errorId = digits.join(""); return errorId; } }; module.exports = functions;