diff --git a/data/commands.json b/data/commands.json new file mode 100644 index 0000000..e92b37c --- /dev/null +++ b/data/commands.json @@ -0,0 +1,273 @@ +[ + { + "name": "subscribe", + "description": "Subscribe to a weather.im room", + "default_member_permissions": 0, + "options": [ + { + "name": "room", + "description": "The room/WFO you want to subscribe to", + "type": 3, + "required": true, + "autocomplete": false + }, + { + "name": "message", + "description": "Custom message to send when alert is sent", + "type": 3, + "required": false + } + ] + }, + { + "name": "setmessage", + "description": "Set a custom message for a room", + "default_member_permissions": 0, + "options": [ + { + "name": "room", + "description": "The room/WFO you want to set a message for", + "type": 3, + "required": true, + "autocomplete": false + }, + { + "name": "message", + "description": "Custom message to send when alert is sent", + "type": 3, + "required": true + } + ] + }, + { + "name": "unsubscribe", + "description": "Unsubscribe from a weather.im room", + "default_member_permissions": 0, + "options": [ + { + "name": "room", + "description": "The room/WFO you want to unsubscribe from", + "type": 3, + "required": true, + "autocomplete": false + } + ] + }, + + { + "name": "list", + "description": "List all subscribed rooms for this channel", + "default_member_permissions": 0 + }, + { + "name": "about", + "description": "About this bot" + }, + { + "name": "rooms", + "description": "List all available rooms" + }, + { + "name": "setupall", + "description": "[OWNER ONLY] Setup channels in a category for all rooms", + "default_member_permissions": 0, + "type": 1 + }, + { + "name": "support", + "description": "Get support for the bot", + "type": 1 + }, + { + "name": "usersubscribe", + "description": "Subscribe to alerts for a room", + "type": 1, + "options": [ + { + "name": "room", + "description": "The room/WFO you want to subscribe to", + "type": 3, + "required": true + }, + { + "name": "filter", + "description": "Filter for the alert", + "type": 3, + "required": false + }, + { + "name": "minpriority", + "description": "Minimum priority to alert for", + "type": 4, + "required": false, + "choices": [ + { + "name": "Any", + "value": 0 + }, + { + "name": "Minimum", + "value": 1 + }, + { + "name": "Low", + "value": 2 + }, + { + "name": "Normal", + "value": 3 + }, + { + "name": "High", + "value": 4 + }, + { + "name": "Very High", + "value": 5 + } + ] + }, + { + "name": "filterevt", + "description": "Filter for event type", + "type": 3, + "required": false + } + ] + }, + { + "name": "userunsubscribe", + "description": "Unsubscribe from alerts for a room", + "type": 1, + "options": [ + { + "name": "room", + "description": "The room/WFO you want to unsubscribe from", + "type": 3, + "required": true + } + ] + }, + { + "name": "userlist", + "description": "List all subscribed alerts for this user", + "type": 1 + }, + { + "name": "outlook", + "description": "Get day 1-8 storm or fire outlook from the SPC", + "type": 1, + "options": [ + { + "name": "day", + "description": "Day of outlook", + "type": 4, + "required": true, + "choices": [ + { + "name": "Day 1", + "value": 0 + }, + { + "name": "Day 2", + "value": 1 + }, + { + "name": "Day 3", + "value": 2 + }, + { + "name": "Day 4", + "value": 3 + }, + { + "name": "Day 5", + "value": 4 + }, + { + "name": "Day 6", + "value": 5 + }, + { + "name": "Day 7", + "value": 6 + }, + { + "name": "Day 8", + "value": 7 + } + ] + }, + { + "name": "type", + "description": "Type of outlook", + "type": 3, + "required": true, + "choices": [ + { + "name": "Fire", + "value": "fire" + }, + { + "name": "Convective", + "value": "convective" + } + ] + }, + { + "name": "population_overlay", + "description": "Whether to add the population overlay", + "type": 5, + "required": false + }, + { + "name": "city_overlay", + "description": "Whether to add the city name overlay", + "type": 5, + "required": false + }, + { + "name": "cwa_overlay", + "description": "Whether to add the County Warning Area overlay", + "type": 5, + "required": false + }, + { + "name": "rfc_overlay", + "description": "Whether to add the River Forecast Center overlay", + "type": 5, + "required": false + }, + { + "name": "interstate_overlay", + "description": "Whether to add the interstate overlay", + "type": 5, + "required": false + }, + { + "name": "county_overlay", + "description": "Whether to add the county lines overlay", + "type": 5, + "required": false + }, + { + "name": "tribal_overlay", + "description": "Whether to add the tribal lands overlay", + "type": 5, + "required": false + }, + { + "name": "artcc_overlay", + "description": "Whether to add the Air Route Traffic Control Centers overlay", + "type": 5, + "required": false + }, + { + "name": "fema_overlay", + "description": "Whether to add the FEMA regions overlay", + "type": 5, + "required": false + } + ] + } +] \ No newline at end of file diff --git a/data/outlook.json b/data/outlook.json index 6e72a92..a6450b3 100644 --- a/data/outlook.json +++ b/data/outlook.json @@ -1,5 +1,5 @@ { - "storm": [ + "convective": [ "https://www.spc.noaa.gov/products/outlook/day1otlk.gif", "https://www.spc.noaa.gov/products/outlook/day2otlk.gif", "https://www.spc.noaa.gov/products/outlook/day3otlk.gif", diff --git a/images/overlays/artcc.png b/images/overlays/artcc.png new file mode 100644 index 0000000..5f2c340 Binary files /dev/null and b/images/overlays/artcc.png differ diff --git a/images/overlays/city.png b/images/overlays/city.png new file mode 100644 index 0000000..d59a183 Binary files /dev/null and b/images/overlays/city.png differ diff --git a/images/overlays/county.png b/images/overlays/county.png new file mode 100644 index 0000000..87282bd Binary files /dev/null and b/images/overlays/county.png differ diff --git a/images/overlays/cwa.png b/images/overlays/cwa.png new file mode 100644 index 0000000..6d16504 Binary files /dev/null and b/images/overlays/cwa.png differ diff --git a/images/overlays/fema.png b/images/overlays/fema.png new file mode 100644 index 0000000..71a018d Binary files /dev/null and b/images/overlays/fema.png differ diff --git a/images/overlays/interstate.png b/images/overlays/interstate.png new file mode 100644 index 0000000..b9db88e Binary files /dev/null and b/images/overlays/interstate.png differ diff --git a/images/overlays/population.png b/images/overlays/population.png new file mode 100644 index 0000000..875db88 Binary files /dev/null and b/images/overlays/population.png differ diff --git a/images/overlays/rfc.png b/images/overlays/rfc.png new file mode 100644 index 0000000..e434339 Binary files /dev/null and b/images/overlays/rfc.png differ diff --git a/images/overlays/tribal.png b/images/overlays/tribal.png new file mode 100644 index 0000000..898ead9 Binary files /dev/null and b/images/overlays/tribal.png differ diff --git a/index.js b/index.js index 67d3124..c2c22b6 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ const wfos = require("./data/wfos.json"); const blacklist = require("./data/blacklist.json"); const events = require("./data/events.json"); const outlookURLs = require("./data/outlook.json"); +const Jimp = require("jimp"); const { client, xml } = require("@xmpp/client"); const fetch = require("node-fetch"); const html = require("html-entities") @@ -546,226 +547,7 @@ discord.on('ready', async () => { }); // Do slash command stuff - const commands = [ - { - "name": "subscribe", - "description": "Subscribe to a weather.im room", - "default_member_permissions": 0, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to subscribe to", - "type": 3, - "required": true, - "autocomplete": false - }, - { - "name": "message", - "description": "Custom message to send when alert is sent", - "type": 3, - "required": false - } - ] - }, - { - "name": "setmessage", - "description": "Set a custom message for a room", - "default_member_permissions": 0, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to set a message for", - "type": 3, - "required": true, - "autocomplete": false - }, - { - "name": "message", - "description": "Custom message to send when alert is sent", - "type": 3, - "required": true - } - ] - }, - { - "name": "unsubscribe", - "description": "Unsubscribe from a weather.im room", - "default_member_permissions": 0, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to unsubscribe from", - "type": 3, - "required": true, - "autocomplete": false - }, - ] - }, - - { - "name": "list", - "description": "List all subscribed rooms for this channel", - "default_member_permissions": 0 - }, - { - "name": "about", - "description": "About this bot" - }, - { - "name": "rooms", - "description": "List all available rooms" - }, - { - "name": "setupall", - "description": "[OWNER ONLY] Setup channels in a category for all rooms", - "default_member_permissions": 0, - "type": 1 - }, - { - "name": "support", - "description": "Get support for the bot", - "type": 1 - }, - // User alert commands - { - "name": "usersubscribe", - "description": "Subscribe to alerts for a room", - "type": 1, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to subscribe to", - "type": 3, - "required": true - }, - { - "name": "filter", - "description": "Filter for the alert", - "type": 3, - "required": false - }, - { - "name": "minpriority", - "description": "Minimum priority to alert for", - "type": 4, - "required": false, - "choices": [ - { - "name": "Any", - "value": 0, - }, - { - "name": "Minimum", - "value": 1, - }, - { - "name": "Low", - "value": 2, - }, - { - "name": "Normal", - "value": 3, - }, - { - "name": "High", - "value": 4, - }, - { - "name": "Very High", - "value": 5, - } - ] - }, - { - "name": "filterevt", - "description": "Filter for event type", - "type": 3, - "required": false - } - ] - }, - { - "name": "userunsubscribe", - "description": "Unsubscribe from alerts for a room", - "type": 1, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to unsubscribe from", - "type": 3, - "required": true - } - ] - }, - { - "name": "userlist", - "description": "List all subscribed alerts for this user", - "type": 1 - }, - { - "name": "outlook", - "description": "Get day 1-8 storm or fire outlook from the SPC", - "type": 1, - "options": [ - { - "name": "day", - "description": "Day of outlook", - "type": 4, - "required": true, - "choices": [ - { - "name": "Day 1", - "value": 0 - }, - { - "name": "Day 2", - "value": 1 - }, - { - "name": "Day 3", - "value": 2 - }, - { - "name": "Day 4", - "value": 3 - }, - { - "name": "Day 5", - "value": 4 - }, - { - "name": "Day 6", - "value": 5 - }, - { - "name": "Day 7", - "value": 6 - }, - { - "name": "Day 8", - "value": 7 - } - ] - }, - { - "name": "type", - "description": "Type of outlook", - "type": 3, - "required": true, - "choices": [ - { - "name": "Fire", - "value": "fire" - }, - { - "name": "Storm", - "value": "storm" - } - ] - } - ] - } - ]; + commands = require("./data/commands.json"); if (config.broadcastify.enabled) { // Add commands to join vc, leave vc, and play stream @@ -1232,26 +1014,74 @@ discord.on("interactionCreate", async (interaction) => { interaction.editReply({ content: "Failed to get outlook", ephemeral: true }); return; } - // debug log toLocalString of timestamps - console.log(issued.toLocaleString()); - // Returns image, send embed with image as attachment (we need to bypass discord cache) res.buffer().then(async (buffer) => { - interaction.editReply({ - embeds: [{ - title: `${toTitleCase(type)} Outlook Day ${day + 1}`, - image: { - url: `attachment://${type}_${day}.png` - }, - color: 0x00ff00 - }], - files: [{ - attachment: buffer, - name: `${type}_${day}.png` - }] + // Check all overlays and add them to image as selected using Jimp + overlays = ["population", "city", "cwa", "rfc", "interstate", "county", "tribal", "artcc", "fema"] + await Jimp.read(buffer).then((image) => { + outImg = image; + cnt = 0; + sendMsg = setTimeout(() => { + interaction.editReply({ + embeds: [{ + title: `${toTitleCase(type)} Outlook Day ${day + 1}`, + image: { + url: `attachment://${type}_${day}.png` + }, + color: 0x00ff00 + }], + files: [{ + attachment: buffer, + name: `${type}_${day}.png` + }] + }); + }, 150) + overlays.forEach((overlay) => { + if (interaction.options.getBoolean(`${overlay}_overlay`)) { + clearTimeout(sendMsg); + Jimp.read(`./images/overlays/${overlay}.png`).then((overlayImage) => { + outImg.composite(overlayImage, 0, 0); + sendMsg = setTimeout(() => { + outImg.getBufferAsync(Jimp.MIME_PNG).then((buffer) => { + interaction.editReply({ + embeds: [{ + title: `${toTitleCase(type)} Outlook Day ${day + 1}`, + image: { + url: `attachment://${type}_${day}.png` + }, + color: 0x00ff00 + }], + files: [{ + attachment: buffer, + name: `${type}_${day}.png` + }] + }); + }); + }, 150) + }); + } + }) + + + + // interaction.editReply({ + // embeds: [{ + // title: `${toTitleCase(type)} Outlook Day ${day + 1}`, + // image: { + // url: `attachment://${type}_${day}.png` + // }, + // color: 0x00ff00 + // }], + // files: [{ + // attachment: buffer, + // name: `${type}_${day}.png` + // }] + // }); }); }); }).catch((err) => { interaction.editReply({ content: "Failed to get outlook", ephemeral: true }); + console.log(`${colors.red("[ERROR]")} Failed to get outlook: ${err.message}`); + console.error(err); }); break; } diff --git a/package.json b/package.json index f379e23..7c13012 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "colors": "^1.4.0", "discord.js": "^14.15.2", "html-entities": "^2.5.2", + "jimp": "^0.22.12", "sodium": "^3.0.2", "sqlite3": "^5.1.7", "ts-node": "^10.9.2",