diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/data/sattelites.json b/data/sattelites.json index 94cda82..c82967e 100644 --- a/data/sattelites.json +++ b/data/sattelites.json @@ -1,30 +1,187 @@ { - "GOES-16": [ - { - "name": "GeoColor", - "url": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/CONUS/GEOCOLOR/latest.jpg" - }, - { - "name": "Infrared", - "url": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/CONUS/13/latest.jpg" - }, - { - "name": "FullDisk", - "url": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/FD/GEOCOLOR/678x678.jpg" + "GOES-16": { + "products": { + "Full Disk": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/FD/GEOCOLOR/1808x1808.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/FD/AirMass/1808x1808.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/FD/13/1808x1808.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/FD/10/1808x1808.jpg" + }, + "Floater 1": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/MESO/M1/GEOCOLOR/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/MESO/M1/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/MESO/M1/10/1000x1000.jpg" + }, + "Floater 2": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/MESO/M2/GEOCOLOR/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/MESO/M2/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/MESO/M2/10/1000x1000.jpg" + }, + "United States": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/CONUS/GEOCOLOR/2500x1500.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/CONUS/AirMass/2500x1500.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/CONUS/13/2500x1500.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/CONUS/10/2500x1500.jpg" + }, + "Canada": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/can/GEOCOLOR/2250x1125.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/can/AirMass/2250x1125.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/can/13/2250x1125.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/can/10/2250x1125.jpg" + }, + "Mexico": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/mex/GEOCOLOR/1000x1000.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/mex/AirMass/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/mex/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/mex/10/1000x1000.jpg" + }, + "US East Coast": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/eus/GEOCOLOR/1000x1000.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/eus/AirMass/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/eus/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/eus/10/1000x1000.jpg" + }, + "Gulf of Mexico": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/gm/GEOCOLOR/1000x1000.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/gm/AirMass/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/gm/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/gm/10/1000x1000.jpg" + }, + "Puerto Rico": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/pr/GEOCOLOR/1200x1200.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/pr/AirMass/1200x1200.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/pr/13/1200x1200.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/pr/10/1200x1200.jpg" + } } - ], - "GOES-18": [ - { - "name": "GeoColor", - "url": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/CONUS/GEOCOLOR/latest.jpg" - }, - { - "name": "Infrared", - "url": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/CONUS/13/latest.jpg" - }, - { - "name": "FullDisk", - "url": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/FD/GEOCOLOR/678x678.jpg" + }, + "GOES-18": { + "products": { + "Full Disk": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/FD/GEOCOLOR/1808x1808.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/FD/AirMass/1808x1808.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/FD/13/1808x1808.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/FD/10/1808x1808.jpg" + }, + "Floater 1": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/MESO/M1/GEOCOLOR/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/MESO/M1/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/MESO/M1/10/1000x1000.jpg" + }, + "Floater 2": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/MESO/M2/GEOCOLOR/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/MESO/M2/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/MESO/M2/10/1000x1000.jpg" + }, + "US West Coast": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/wus/GEOCOLOR/1000x1000.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/wus/AirMass/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/wus/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/wus/10/1000x1000.jpg" + }, + "Hawaii": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/hi/GEOCOLOR/1200x1200.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/hi/AirMass/1200x1200.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/hi/13/1200x1200.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/hi/10/1200x1200.jpg" + }, + "Alaska": { + "Visible": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/ak/GEOCOLOR/1000x1000.jpg", + "Airmass": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/ak/AirMass/1000x1000.jpg", + "Infrared": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/ak/13/1000x1000.jpg", + "Water Vapor": "https://cdn.star.nesdis.noaa.gov/GOES18/ABI/SECTOR/ak/10/1000x1000.jpg" + } } - ] + }, + "Himawari": { + "products": { + "Full Disk": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/full_disk_ahi_true_color.jpg", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/full_disk_ahi_rgb_airmass.jpg", + "Infrared": "https://www.ssec.wisc.edu/data/geo/images/himawari09/latest-himawari09_11_fd.gif", + "Water Vapor": "https://www.ssec.wisc.edu/data/geo/images/himawari09/latest-himawari09_10_fd.gif" + }, + "Floater 1": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest/himawari-8/floater_02_geocolor.pngv", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest/himawari-8/floater_02_rgb_airmass.png" + }, + "American Samoa": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/american_samoa_ahi_natural_color.png", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/american_samoa_ahi_rgb_airmass.png" + }, + "Australia": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest/himawari-8/australia_true_color.jpg", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/australia_ahi_rgb_airmass.png" + }, + "New Zealand": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/new_zealand_ahi_natural_color.png", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/new_zealand_ahi_rgb_airmass.png" + }, + "Guam": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/guam_ahi_natural_color.png", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/guam_ahi_rgb_airmass.png" + }, + "Hawaii": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/hawaii_ahi_natural_color.png" + }, + "Japan": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/japan_ahi_natural_color.png", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/japan_ahi_rgb_airmass.png" + }, + "Russia": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest/himawari-8/eastern_russia_true_color.jpg" + }, + "China": { + "Visible": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/eastern_china_ahi_natural_color.png", + "Airmass": "https://rammb.cira.colostate.edu/ramsdis/online/images/latest_hi_res/himawari-8/eastern_china_ahi_rgb_airmass.png" + } + } + }, + "EWS-G2": { + "products": { + "Full Disk": { + "Visible": "https://www.ssec.wisc.edu/data/geo/images/ews-g1/latest_ews-g1_01_fd.gif", + "Water Vapor": "https://www.ssec.wisc.edu/data/geo/images/ews-g1/latest_ews-g1_03_fd.gif" + } + } + }, + "FY-2G": { + "products": { + "Full Disk": { + "Visible": "https://www.ssec.wisc.edu/data/geo/images/fy2g/latest_fy2g_01_fd.gif", + "Infrared": "https://www.ssec.wisc.edu/data/geo/images/fy2g/latest_fy2g_02_fd.gif", + "Water Vapor": "https://www.ssec.wisc.edu/data/geo/images/fy2g/latest_fy2g_04_fd.gif" + } + } + }, + "GK-2A": { + "products": { + "Full Disk": { + "Infrared": "https://kiwiweather.com/gk-2a/FD_sanchez.jpg" + } + } + }, + "Meteosat 9": { + "products": { + "Full Disk": { + "Visible": "https://www.ssec.wisc.edu/data/geo/images/met-iodc/latest_met-iodc_01_fd.jpg", + "Infrared": "https://www.ssec.wisc.edu/data/geo/images/met-iodc/latest_met-iodc_04_fd.jpg", + "Water Vapor": "https://www.ssec.wisc.edu/data/geo/images/met-iodc/latest_met-iodc_06_fd.jpg" + } + } + }, + "Meteosat 10": { + "products": { + "Full Disk": { + "Visible": "https://www.ssec.wisc.edu/data/geo/images/met-prime/latest_met-prime_01_fd.gif", + "Infrared": "https://www.ssec.wisc.edu/data/geo/images/met-prime/latest_met-prime_04_fd.gif", + "Water Vapor": "https://www.ssec.wisc.edu/data/geo/images/met-prime/latest_met-prime_06_fd.gif" + }, + "Europe": { + "Visible": "https://www.ssec.wisc.edu/data/geo/images/met-prime/latest_met-prime_01_euro.gif", + "Infrared": "https://www.ssec.wisc.edu/data/geo/images/met-prime/latest_met-prime_04_euro.gif", + "Water Vapor": "https://www.ssec.wisc.edu/data/geo/images/met-prime/latest_met-prime_06_euro.gif" + } + } + } } \ No newline at end of file diff --git a/index.js b/index.js index db9f7c1..383c9df 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,9 @@ const Discord = require("discord.js"); const dVC = require("@discordjs/voice"); const colors = require("colors"); const sqlite3 = require("sqlite3").verbose(); + +satMessages = {}; + // Setup Discord const discord = new Discord.Client({ intents: [ @@ -402,7 +405,7 @@ xmpp.on("stanza", (stanza) => { { type: 2, style: 1, - custom_id: product_id_raw, + custom_id: `product|${product_id_raw}`, label: "Product Text", emoji: { name: "📄" @@ -605,10 +608,11 @@ discord.on('ready', async () => { "required": true, "choices": [] } - ] + ], + "integration_types": [0,1], + "contexts": [0, 1, 2] } for (const key in sattelites) { - // Push the key to the choices array satCommand.options[0].choices.push({ "name": key, "value": key @@ -1252,44 +1256,38 @@ discord.on("interactionCreate", async (interaction) => { sat = interaction.options.getString("sattelite"); if (!sattelites[sat]) return interaction.reply({ content: "Invalid satellite", ephemeral: true }); // Fetch all the images - await interaction.deferReply(); - imageBuffers = {}; - embeds = []; - files = []; - sattelites[sat].forEach(async (imgData) => { - // Get a buffer for the data, and put that in imageBuffers with the "name" as the key - fetch(imgData.url).then((res) => { - if (res.status !== 200) { - interaction.editReply({ content: "Failed to get satellite images", ephemeral: true }); - return; - } - res.buffer().then((buffer) => { - imageBuffers[imgData.name] = buffer; - files.push({ - attachment: buffer, - name: `${imgData.name}.jpg` - }); - embeds.push({ - title: `${sat} ${imgData.name}`, - image: { - url: `attachment://${imgData.name}.jpg` + productOptions = [] + await (() => { + for (const key in sattelites[sat].products) { + // make a discord customid safe id for the product name, add it to the sattelites object + sattelites[sat].products[key].customid = key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase(); + productOptions.push({ + label: key, + value: sattelites[sat].products[key].customid + }) + } + console.log(JSON.stringify(productOptions, null, 2)) + })(); + satMessages[interaction.id] = { + sat + } + await interaction.reply({ + content: "Choose a product", + components: [ + { + type: 1, + components: [ + { + type: 3, + custom_id: `satproduct|${interaction.id}`, + label: "Product", + // map options to product names + options: productOptions } - }); - // Check if we have all the images - if (Object.keys(imageBuffers).length === sattelites[sat].length) { - // Send the images - interaction.editReply({ - embeds, - files - }); - } - }); - }).catch((err) => { - interaction.editReply({ content: "Failed to get satellite images", ephemeral: true }); - console.log(`${colors.red("[ERROR]")} Failed to get satellite images: ${err.message}`); - console.error(err); - }); - }); + ] + } + ] + }) break; case "forecast": @@ -1310,36 +1308,140 @@ discord.on("interactionCreate", async (interaction) => { } case Discord.InteractionType.MessageComponent: - if (interaction.customId) { - const product_id = interaction.customId; - url = `https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id}`; - await interaction.deferReply({ ephemeral: true }); - fetch(url).then((res) => { - if (res.status !== 200) { - interaction.reply({ content: "Failed to get product text", ephemeral: true }); - return; + if (!interaction.customId) return; + switch (interaction.customId.split("|")[0]) { + case "product": + if (interaction.customId) { + const product_id = interaction.customId.split("|")[1]; + url = `https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id}`; + await interaction.deferReply({ ephemeral: true }); + fetch(url).then((res) => { + if (res.status !== 200) { + interaction.reply({ content: "Failed to get product text", ephemeral: true }); + return; + } + // Retruns raw text, paginate it into multiple embeds if needed + res.text().then(async (text) => { + const pages = text.match(/[\s\S]{1,1900}(?=\n|$)/g); + // const embeds = pages.map((page, ind) => ({ + // title: `Product Text for ${product_id} Pg ${ind + 1}/${pages.length}`, + // description: `\`\`\`${page}\`\`\``, + // color: 0x00ff00 + // })); + const messages = pages.map((page, ind) => { + return `\`\`\`${page}\`\`\`` + }) + messages.forEach(async (message) => { + interaction.followUp({ content: message, ephemeral: true }); + }) + }); + }).catch((err) => { + interaction.reply({ content: "Failed to get product text", ephemeral: true }); + console.log(`${colors.red("[ERROR]")} Failed to get product text: ${err.message}`); + }); } - // Retruns raw text, paginate it into multiple embeds if needed - res.text().then(async (text) => { - const pages = text.match(/[\s\S]{1,1900}(?=\n|$)/g); - // const embeds = pages.map((page, ind) => ({ - // title: `Product Text for ${product_id} Pg ${ind + 1}/${pages.length}`, - // description: `\`\`\`${page}\`\`\``, - // color: 0x00ff00 - // })); - const messages = pages.map((page, ind) => { - return `\`\`\`${page}\`\`\`` - }) - messages.forEach(async (message) => { - interaction.followUp({ content: message, ephemeral: true }); - }) + break; + case "satproduct": + satData = satMessages[interaction.customId.split("|")[1]]; + sat = satData.sat + product = interaction.values[0]; + // find the original product name + product_name = Object.keys(sattelites[sat].products).find(key => sattelites[sat].products[key].customid === product); + imageOptions = [] + satMessages[interaction.customId.split("|")[1]] = { + sat, + product, + product_name, + images: {} + } + await (() => { + // for key, value in sattelites[sat].products[product_name] + console.log(product_name) + for (const key in sattelites[sat].products[product_name]) { + // make a discord customid safe id for the product name, add it to the sattelites object + //console.log(sattelites[sat].products[product_name]) + if (key === "customid") continue; + satMessages[interaction.customId.split("|")[1]].images[key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()] = sattelites[sat].products[product_name][key]; + imageOptions.push({ + label: key, + value: key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase() + }) + } + })(); + interaction.deferReply(); + await interaction.message.edit({ + content: "Choose an image to view", + components: [ + { + type: 1, + components: [ + { + type: 3, + custom_id: `satproduct2|${interaction.customId.split("|")[1]}`, + label: "Image", + // map options to product names + options: imageOptions + } + ] + } + ] + }).then(() => { + interaction.deleteReply(); }); - }).catch((err) => { - interaction.reply({ content: "Failed to get product text", ephemeral: true }); - console.log(`${colors.red("[ERROR]")} Failed to get product text: ${err.message}`); - }); + break; + case "satproduct2": + satData = satMessages[interaction.customId.split("|")[1]]; + sat = satData.sat; + product = satData.product; + product_name = satData.product_name; + image = interaction.values[0]; + url = satData.images[image]; + // get filename from url + filename = url.split("/").pop(); + interaction.deferReply(); + // Get the image + fetch(url).then((res) => { + if (res.status !== 200) { + interaction.message.edit({ content: "Failed to get image", ephemeral: true }).then(() => { + interaction.deleteReply(); + }); + return; + } + embeds = []; + files = []; + + res.buffer().then(async (buffer) => { + files.push({ + attachment: buffer, + name: filename + }) + embeds.push({ + title: `${sat}/${product_name}/${image}`, + image: { + url: `attachment://${filename}` + }, + color: 0x00ff00 + }); + interaction.message.edit({ + embeds, + files, + components: [], + content: null + }).then(() => { + interaction.deleteReply(); + }); + } + ); + }).catch((err) => { + interaction.message.edit({ content: "Failed to get image", ephemeral: true }).then(() => { + interaction.deleteReply(); + }); + console.log(`${colors.red("[ERROR]")} Failed to get image: ${err.stack}`); + }); + break; } break; + } @@ -1379,7 +1481,7 @@ discord.on("guildDelete", (guild) => { }) process.on("unhandledRejection", (error, promise) => { - console.log(`${colors.red("[ERROR]")} Unhandled Rejection @ ${promise}: ${error}`); + console.log(`${colors.red("[ERROR]")} Unhandled Rejection @ ${promise}: ${error.stack}`); // create errors folder if it doesnt exist if (!fs.existsSync("./error")) { fs.mkdirSync("./error");