Compare commits

...

40 commits

Author SHA1 Message Date
MoSiren 664e00b7f4 Update data/events.json
Some checks failed
ptero-push / build (push) Has been cancelled
updated some pri codes
2025-04-18 19:35:53 -06:00
MoSiren cce9b12645 Update data/events.json
Some checks are pending
ptero-push / build (push) Waiting to run
Flash Flood Warning Is Level 5
2025-04-18 19:30:46 -06:00
MoSiren c82ab68c1e Nexlabs Outlooks
Some checks failed
ptero-push / build (push) Has been cancelled
2025-03-13 23:51:03 -06:00
Christopher Cookman a543386394 Made the same mistake twice, dang
Some checks failed
ptero-push / build (push) Has been cancelled
2025-02-12 07:57:20 -07:00
Christopher Cookman 1ae72ac979 hotfix
Some checks are pending
ptero-push / build (push) Waiting to run
2025-02-12 07:56:27 -07:00
Christopher Cookman 1a7c1735f4 Fix log?
Some checks are pending
ptero-push / build (push) Waiting to run
2025-02-12 07:54:59 -07:00
Christopher Cookman 5b487125aa Update some logging stuff
Some checks are pending
ptero-push / build (push) Waiting to run
2025-02-12 07:51:27 -07:00
Christopher Cookman 770813b4a7 Whooooops
Some checks failed
ptero-push / build (push) Has been cancelled
2025-02-09 10:30:11 -07:00
Christopher Cookman ded7a2373c Attempt to not throw error when we cant DM a user!
Some checks are pending
ptero-push / build (push) Waiting to run
2025-02-09 10:29:05 -07:00
Christopher Cookman 79ae2f4c25 Fix sat typo, mb
Some checks are pending
ptero-push / build (push) Waiting to run
2025-02-09 10:23:15 -07:00
Christopher Cookman e02faaab18 Add bypass to deletion for main guild
Some checks failed
ptero-push / build (push) Has been cancelled
2025-02-03 05:04:21 -07:00
Christopher Cookman bd275403e9 Add discord message when unknown event type trips
Some checks failed
ptero-push / build (push) Has been cancelled
2025-01-13 14:36:08 -07:00
Christopher Cookman 9b80f79436 Add Pilot Reports to events 2025-01-13 14:35:07 -07:00
Christopher Cookman 4bb679cef8 Add perm check to subscribe command
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-13 14:24:01 -07:00
Christopher Cookman e952ec60e7 Notify guild owners and remove subs
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 23:36:26 -07:00
Christopher Cookman 0227979176 Add full sub info to permission errors
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:18:24 -07:00
Christopher Cookman 9f31d18a6f Smol fix
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:06:31 -07:00
Christopher Cookman d491fda5c8 Im dumb
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:04:56 -07:00
Christopher Cookman 96912d325a Make embed smaller
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:04:09 -07:00
Christopher Cookman 00f97fd6e6 Damn, busy night lol
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:02:13 -07:00
Christopher Cookman 09f3fc957c Fix issue
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:01:17 -07:00
Christopher Cookman cbb1842100 Add message to log channel about failed sends
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 03:00:31 -07:00
Christopher Cookman f763a95472 bwuuuuh
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 02:54:21 -07:00
Christopher Cookman d88188182c Bwuh
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 02:52:16 -07:00
Christopher Cookman 8b94e7e3f8 Possibly notify of bad perms?
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 02:50:54 -07:00
Christopher Cookman d653bc3e90 Add discord error logs
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 02:41:40 -07:00
Christopher Cookman b5bf06a38d Fix that
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 02:36:44 -07:00
Christopher Cookman ae63a0d52d Add .catch to sending discord messages. Hopefully this will fix the log flooding lol
Some checks are pending
ptero-push / build (push) Waiting to run
2025-01-12 02:31:17 -07:00
MoSiren 73e42e2288 Updated WSW.
Some checks failed
ptero-push / build (push) Has been cancelled
2024-11-21 17:26:34 -07:00
MoSiren 9afdd5626e Update data/events.json
Some checks failed
ptero-push / build (push) Has been cancelled
2024-09-27 13:48:25 -06:00
MoSiren f6acab4d20 Update data/events.json
Some checks are pending
ptero-push / build (push) Waiting to run
NPW 3
2024-09-27 12:41:01 -06:00
MoSiren b10308ef36 Update data/events.json
Some checks failed
ptero-push / build (push) Has been cancelled
Fixed Hurricane Warnings and Tropical Storm Warnings that Show at lowest level. Now set to High instead of Lowest
2024-09-26 07:57:25 -06:00
Christopher Cookman aa8fe9498f
Update
Some checks failed
ptero-push / build (push) Has been cancelled
- Use cached URL for nwrstreams
2024-08-16 03:11:16 -06:00
Christopher Cookman d48fe3085a
Update
Some checks are pending
ptero-push / build (push) Waiting to run
- Make NWRplay use new GWES icecast server!
2024-08-15 23:09:16 -06:00
Christopher Cookman 662e0e775c
Fix
Some checks are pending
ptero-push / build (push) Waiting to run
- Restart after 10 minutes of inactivity from weather.im
2024-08-15 22:35:44 -06:00
Christopher Cookman 845fead37a
Backend Update
Some checks are pending
ptero-push / build (push) Waiting to run
- Send a message to the user who added the bot to a guild with support link
2024-08-15 22:33:18 -06:00
Christopher Cookman 70c30420fc uh
All checks were successful
ptero-push / build (push) Successful in 11s
2024-07-31 21:08:43 -06:00
Christopher Cookman 98673be5c7
# Major Bug Fix
Some checks failed
ptero-push / build (push) Has been cancelled
- "You had it set to 'W' for Wumbo, when you should've had it set to 'M' for mini."

Fixed a small issue involving capitalization.
TL;DR Fixed evtFilter for guild channels :)
2024-07-16 21:51:11 -06:00
Christopher Cookman aac1420964
guess it cant be a dm thing
Some checks are pending
ptero-push / build (push) Waiting to run
2024-07-15 20:05:50 -06:00
Christopher Cookman 7a12ed05d3
G U H
Some checks are pending
ptero-push / build (push) Waiting to run
2024-07-15 20:03:01 -06:00
7 changed files with 564 additions and 155 deletions

1
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -91,6 +91,4 @@
"zsechat@conference.weather.im", "zsechat@conference.weather.im",
"zdcchat@conference.weather.im", "zdcchat@conference.weather.im",
"znychat@conference.weather.im" "znychat@conference.weather.im"
] ]

View file

@ -217,7 +217,7 @@
}, },
"DSW": { "DSW": {
"text": "Dust Storm Warning", "text": "Dust Storm Warning",
"priority": 5 "priority": 4
}, },
"EFP": { "EFP": {
"priority": 1, "priority": 1,
@ -365,7 +365,7 @@
}, },
"FFW": { "FFW": {
"text": "Flash Flood Warning", "text": "Flash Flood Warning",
"priority": 4 "priority": 5
}, },
"FLN": { "FLN": {
"priority": 1, "priority": 1,
@ -385,7 +385,7 @@
}, },
"FRW": { "FRW": {
"text": "Fire Warning", "text": "Fire Warning",
"priority": 4 "priority": 3
}, },
"FSH": { "FSH": {
"priority": 1, "priority": 1,
@ -680,7 +680,7 @@
"text": "Data Mgt Message" "text": "Data Mgt Message"
}, },
"NPW": { "NPW": {
"priority": 1, "priority": 3,
"text": "Non-Precipitation Warnings / Watches / Advisories" "text": "Non-Precipitation Warnings / Watches / Advisories"
}, },
"NSH": { "NSH": {
@ -1160,7 +1160,7 @@
"text": "Tropical Cyclone Update" "text": "Tropical Cyclone Update"
}, },
"TCV": { "TCV": {
"priority": 1, "priority": 4,
"text": "Tropical Cyclone Watch/Warning Break Points" "text": "Tropical Cyclone Watch/Warning Break Points"
}, },
"TIB": { "TIB": {
@ -1308,7 +1308,7 @@
"text": "Routine Space Environment Product Issued Weekly" "text": "Routine Space Environment Product Issued Weekly"
}, },
"WOU": { "WOU": {
"priority": 4, "priority": 5,
"text": "Tornado/Severe Thunderstorm Watch" "text": "Tornado/Severe Thunderstorm Watch"
}, },
"WS1": { "WS1": {
@ -1345,7 +1345,7 @@
}, },
"WSW": { "WSW": {
"text": "Winter Storm Warning", "text": "Winter Storm Warning",
"priority": 5 "priority": 4
}, },
"WWA": { "WWA": {
"priority": 1, "priority": 1,
@ -1365,11 +1365,11 @@
}, },
"CFA": { "CFA": {
"text": "Coastal Flood Watch", "text": "Coastal Flood Watch",
"priority": 4 "priority": 3
}, },
"FLA": { "FLA": {
"text": "Flood Watch", "text": "Flood Watch",
"priority": 2 "priority": 3
}, },
"HWA": { "HWA": {
"text": "High Wind Watch", "text": "High Wind Watch",
@ -1389,7 +1389,7 @@
}, },
"SVA": { "SVA": {
"text": "Severe Thunderstorm Watch", "text": "Severe Thunderstorm Watch",
"priority": 4 "priority": 5
}, },
"TOA": { "TOA": {
"text": "Tornado Watch", "text": "Tornado Watch",
@ -1405,7 +1405,7 @@
}, },
"TSA": { "TSA": {
"text": "Tsunami Watch", "text": "Tsunami Watch",
"priority": 4 "priority": 5
}, },
"TSW": { "TSW": {
"text": "Tsunami Warning", "text": "Tsunami Warning",
@ -1522,6 +1522,9 @@
"REP": { "REP": {
"text": "RECCO Observations (tropical cyclone)", "text": "RECCO Observations (tropical cyclone)",
"priority": 3 "priority": 3
},
"PIR": {
"text": "Pilot Reports",
"priority": 1
} }
} }

View file

@ -1,13 +1,13 @@
{ {
"convective": [ "convective": [
"https://www.spc.noaa.gov/products/outlook/day1otlk.gif", "https://weather.cod.edu/cdata/text/images/spc/co/day1/categorical/spccoday1.categorical.latest.png",
"https://www.spc.noaa.gov/products/outlook/day2otlk.gif", "https://climate.cod.edu/data/text/images/spc/co/day2/categorical/spccoday2.categorical.latest.png",
"https://www.spc.noaa.gov/products/outlook/day3otlk.gif", "https://climate.cod.edu/data/text/images/spc/co/day3/categorical/spccoday3.categorical.latest.png",
"https://www.spc.noaa.gov/products/exper/day4-8/day4prob.gif", "https://climate.cod.edu/data/text/images/spc/co/day4/severe/spccoday4.severe.latest.png",
"https://www.spc.noaa.gov/products/exper/day4-8/day5prob.gif", "https://climate.cod.edu/data/text/images/spc/co/day5/severe/spccoday5.severe.latest.png",
"https://www.spc.noaa.gov/products/exper/day4-8/day6prob.gif", "https://climate.cod.edu/data/text/images/spc/co/day6/severe/spccoday6.severe.latest.png",
"https://www.spc.noaa.gov/products/exper/day4-8/day7prob.gif", "https://climate.cod.edu/data/text/images/spc/co/day7/severe/spccoday7.severe.latest.png",
"https://www.spc.noaa.gov/products/exper/day4-8/day8prob.gif" "https://climate.cod.edu/data/text/images/spc/co/day8/severe/spccoday8.severe.latest.png"
], ],
"fire": [ "fire": [
"https://www.spc.noaa.gov/products/exper/fire_wx/imgs/day1otlk_fire.gif", "https://www.spc.noaa.gov/products/exper/fire_wx/imgs/day1otlk_fire.gif",

187
data/satellites.json Normal file
View file

@ -0,0 +1,187 @@
{
"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": {
"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"
}
}
}
}

View file

@ -1,30 +0,0 @@
{
"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-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"
}
]
}

456
index.js
View file

@ -6,8 +6,8 @@ const wfos = require("./data/wfos.json");
const blacklist = require("./data/blacklist.json"); const blacklist = require("./data/blacklist.json");
const events = require("./data/events.json"); const events = require("./data/events.json");
const outlookURLs = require("./data/outlook.json"); const outlookURLs = require("./data/outlook.json");
const sattelites = require("./data/sattelites.json"); const satellites = require("./data/satellites.json");
const nwrstreams = require("./data/nwrstreams.json") const nwrstreams = {callsigns:{}};
const Jimp = require("jimp"); const Jimp = require("jimp");
const { client, xml } = require("@xmpp/client"); const { client, xml } = require("@xmpp/client");
const fetch = require("node-fetch"); const fetch = require("node-fetch");
@ -16,8 +16,12 @@ const Discord = require("discord.js");
const dVC = require("@discordjs/voice"); const dVC = require("@discordjs/voice");
const colors = require("colors"); const colors = require("colors");
const sqlite3 = require("sqlite3").verbose(); const sqlite3 = require("sqlite3").verbose();
satMessages = {};
// Setup Discord // Setup Discord
const discord = new Discord.Client({ const discord = new Discord.Client({
intents: [ intents: [
"Guilds", "Guilds",
"GuildVoiceStates", "GuildVoiceStates",
@ -32,7 +36,6 @@ const rest = new REST({
version: '10' version: '10'
}).setToken(config.discord.token); }).setToken(config.discord.token);
// Setup SQlite DB // Setup SQlite DB
const db = new sqlite3.Database("channels.db", (err) => { const db = new sqlite3.Database("channels.db", (err) => {
if (err) { if (err) {
@ -40,8 +43,9 @@ const db = new sqlite3.Database("channels.db", (err) => {
} }
console.log(`${colors.cyan("[INFO]")} Connected to the database`); console.log(`${colors.cyan("[INFO]")} Connected to the database`);
// Create tables if they dont exist // Create tables if they dont exist
db.run(`CREATE TABLE IF NOT EXISTS channels (channelid TEXT, iemchannel TEXT, custommessage TEXT, minPriority INTEGER, "filter" TEXT, filterevt TEXT);`); db.run(`CREATE TABLE IF NOT EXISTS channels (channelid TEXT, iemchannel TEXT, custommessage TEXT, minPriority INTEGER, "filter" TEXT, filterEvt TEXT);`);
db.run(`CREATE TABLE IF NOT EXISTS userAlerts (userid TEXT, iemchannel TEXT, filter TEXT, filterEvt TEXT, minPriority INT, custommessage TEXT);`); db.run(`CREATE TABLE IF NOT EXISTS userAlerts (userid TEXT, iemchannel TEXT, filter TEXT, filterEvt TEXT, minPriority INT, custommessage TEXT);`);
db.run(`ALTER TABLE channels RENAME COLUMN filterevt TO filterEvt;`)
}); });
@ -260,6 +264,24 @@ var errCount = 0;
const curUUID = generateUUID(); const curUUID = generateUUID();
// nwrstreams setup
// get icecast json data
const fetchNWRstreams = () => {
fetch("https://icestats.weatherradio.org/").then((res) => {
res.json().then((json) => {
json.icestats.source.forEach((source) => {
nwrstreams.callsigns[source.server_name] = source.listenurl;
});
});
console.log(`${colors.cyan("[INFO]")} Fetched NWR streams`);
}).catch((err) => {
console.error(err);
});
}
fetchNWRstreams();
setInterval(fetchNWRstreams, 5 * 60 * 1000); // Every 5 minutes
const xmpp = client({ const xmpp = client({
service: "xmpp://conference.weather.im", service: "xmpp://conference.weather.im",
domain: "weather.im", domain: "weather.im",
@ -286,6 +308,8 @@ xmpp.on("offline", () => {
}) })
}); });
var restartTimer = null;
xmpp.on("stanza", (stanza) => { xmpp.on("stanza", (stanza) => {
// Debug stuff // Debug stuff
if (config.debug >= 2) console.log(`${colors.magenta("[DEBUG]")} Stanza: ${stanza.toString()}`); if (config.debug >= 2) console.log(`${colors.magenta("[DEBUG]")} Stanza: ${stanza.toString()}`);
@ -311,6 +335,11 @@ xmpp.on("stanza", (stanza) => {
} }
// Get new messages and log them, ignore old messages // Get new messages and log them, ignore old messages
if (stanza.is("message") && stanza.attrs.type === "groupchat") { if (stanza.is("message") && stanza.attrs.type === "groupchat") {
clearTimeout(restartTimer)
restartTimer = setTimeout(() => {
console.log(`${colors.red("[FATAL]")} No messages from weather.im in 10 minutes, restarting!!!!!!!!!!!`)
process.exit(1)
}, 600000)
// Stops spam from getting old messages // Stops spam from getting old messages
if (startup) return; if (startup) return;
// Get channel name // Get channel name
@ -331,6 +360,16 @@ xmpp.on("stanza", (stanza) => {
evt = { name: "Unknown", priority: 3 } evt = { name: "Unknown", priority: 3 }
console.log(`${colors.red("[ERROR]")} Unknown event type: ${product_id.pil.substring(0, 3)}. Fix me`); console.log(`${colors.red("[ERROR]")} Unknown event type: ${product_id.pil.substring(0, 3)}. Fix me`);
console.log(`${colors.magenta("[DEBUG]")} ${bodyData.string}`) console.log(`${colors.magenta("[DEBUG]")} ${bodyData.string}`)
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
logChannel.send({
embeds: [
{
title: "Unknown Event Type",
description: `Unknown event type: ${product_id.pil.substring(0, 3)}. Please check the logs for more details.`,
color: 0xff0000
}
]
});
} }
evt.code = product_id.pil.substring(0, 3); evt.code = product_id.pil.substring(0, 3);
@ -338,13 +377,14 @@ xmpp.on("stanza", (stanza) => {
const now = new Date(); const now = new Date();
const diff = (now - product_id.timestamp) / 1000 / 60; const diff = (now - product_id.timestamp) / 1000 / 60;
if (diff > 3) return; if (diff > 3) return;
if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} New message from ${fromChannel}`); // if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} New message from ${fromChannel}`);
console.log(`${colors.cyan("[INFO]")} ${getWFOByRoom(fromChannel).location} - ${evt.text} - ${product_id.timestamp}`);
messages++; messages++;
// Handle NTFY // Handle NTFY
if (config.ntfy.enabled) { if (config.ntfy.enabled) {
if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} Sending NTFY for ${config.ntfy.prefix}${fromChannel}`) //if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} Sending NTFY for ${config.ntfy.prefix}${fromChannel}`)
ntfyBody = { ntfyBody = {
"topic": `${config.ntfy.prefix}${fromChannel}`, "topic": `${config.ntfy.prefix}${fromChannel}`,
"message": bodyData.string, "message": bodyData.string,
@ -362,7 +402,7 @@ xmpp.on("stanza", (stanza) => {
'Authorization': `Bearer ${config.ntfy.token}` 'Authorization': `Bearer ${config.ntfy.token}`
} }
}).then((res) => { }).then((res) => {
if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} NTFY sent for ${config.ntfy.prefix}${fromChannel} with status ${res.status} ${res.statusText}`); //if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} NTFY sent for ${config.ntfy.prefix}${fromChannel} with status ${res.status} ${res.statusText}`);
if (res.status !== 200) console.log(`${colors.red("[ERROR]")} NTFY failed for ${config.ntfy.prefix}${fromChannel} with status ${res.status} ${res.statusText}`); if (res.status !== 200) console.log(`${colors.red("[ERROR]")} NTFY failed for ${config.ntfy.prefix}${fromChannel} with status ${res.status} ${res.statusText}`);
@ -402,7 +442,7 @@ xmpp.on("stanza", (stanza) => {
{ {
type: 2, type: 2,
style: 1, style: 1,
custom_id: product_id_raw, custom_id: `product|${product_id_raw}`,
label: "Product Text", label: "Product Text",
emoji: { emoji: {
name: "📄" name: "📄"
@ -418,7 +458,7 @@ xmpp.on("stanza", (stanza) => {
console.log(`${colors.red("[ERROR]")} ${err.message}`); console.log(`${colors.red("[ERROR]")} ${err.message}`);
} }
if (!rows) return; // No channels to alert if (!rows) return; // No channels to alert
rows.forEach((row) => { rows.forEach(async (row) => {
// Get Filters as arrays // Get Filters as arrays
if (!row.filterEvt) row.filterEvt = ""; if (!row.filterEvt) row.filterEvt = "";
if (!row.filter) row.filter = ""; if (!row.filter) row.filter = "";
@ -444,6 +484,54 @@ xmpp.on("stanza", (stanza) => {
console.error(err); console.error(err);
}).then((msg) => { }).then((msg) => {
if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost(); if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost();
}).catch((err) => {
console.log(`${colors.yellow("[WARN]")} Failed to send message to ${channel.guild.name}/${channel.name} (${channel.guild.id}/${channel.id})`);
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
logChannel.send({
embeds: [
{
title: "Failed to send message",
description: `There is likely an issue with permissions. Please notify the server owner if possible.
Guild: ${channel.guild.name} (${channel.guild.id})
Channel: ${channel.name} (${channel.id})
Guild Owner: <@${channel.guild.ownerId}> (${channel.guild.ownerId})
Sub Info: \`\`\`json\n${JSON.stringify(row)}\`\`\``,
color: 0xff0000
}
]
});
discord.users.fetch(channel.guild.ownerId).then((user) => {
user.send({
embeds: [
{
title: "Issue with your subscribed channel.",
description: `There is likely an issue with permissions. Please check that I can send messages in <#${channel.id}>\nYour subscription has been removed, and you will need to resubscribe to get alerts.`,
color: 0xff0000,
fields: [
{
name: "Guild",
value: `${channel.guild.name} (${channel.guild.id})`
},
{
name: "Channel",
value: `${channel.name} (${channel.id})`
}
]
}
]
}).catch((err) => {
console.log(`${colors.red("[ERROR]")} Failed to send message to ${channel.guild.ownerId}`);
}).then(() => {
if (channel.guildId == config.discord.mainGuild) return;
db.run(`DELETE FROM channels WHERE channelid = ? AND iemchannel = ?`, [channel.id, fromChannel], (err) => {
if (err) {
console.error(err.message);
}
console.log(`${colors.cyan("[INFO]")} Deleted channel ${channel.id} from database`);
});
})
});
}); });
}); });
}).catch((err) => { }).catch((err) => {
@ -489,6 +577,27 @@ xmpp.on("stanza", (stanza) => {
thisMsg.content = row.custommessage || null; thisMsg.content = row.custommessage || null;
user.send(thisMsg).catch((err) => { user.send(thisMsg).catch((err) => {
console.error(err); console.error(err);
}).catch((err) => {
console.log(`${colors.yellow("[WARN]")} Failed to send message to ${user.tag} (${user.id})`);
const logChannel = discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.logChannel);
logChannel.send({
embeds: [
{
title: "Failed to send DM",
description: `User may have DMs disabled, or bot doesnt' share a server anymore!.
User: ${user.tag} (${user.id})
Sub Info: \`\`\`json\n${JSON.stringify(row)}\`\`\``,
color: 0xff0000
}
]
}).then(() => {
db.run(`DELETE FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [user.id, fromChannel], (err) => {
if (err) {
console.error(err.message);
}
console.log(`${colors.cyan("[INFO]")} Deleted user ${user.id} from database`);
});
})
}); });
}); });
}).catch((err) => { }).catch((err) => {
@ -595,20 +704,19 @@ discord.on('ready', async () => {
commands = require("./data/commands.json"); commands = require("./data/commands.json");
// Add dynamic commands (based on datas files) // Add dynamic commands (based on datas files)
satCommand = { satCommand = {
"name": "sattelite", "name": "satellite",
"description": "Get the latest sattelite images from a given sattelite", "description": "Get the latest satellite images from a given satellite",
"options": [ "options": [
{ {
"name": "sattelite", "name": "satellite",
"description": "The sattelite to get images from", "description": "The satellite to get images from",
"type": 3, "type": 3,
"required": true, "required": true,
"choices": [] "choices": []
} }
] ]
} }
for (const key in sattelites) { for (const key in satellites) {
// Push the key to the choices array
satCommand.options[0].choices.push({ satCommand.options[0].choices.push({
"name": key, "name": key,
"value": key "value": key
@ -683,22 +791,16 @@ discord.on('ready', async () => {
"description": "The URL of the stream to play", "description": "The URL of the stream to play",
"type": 3, "type": 3,
"required": true, "required": true,
"choices": [] "autocomplete": true
} }
] ]
} }
for (const key in nwrstreams.callsigns) {
nwrplayCommand.options[0].choices.push({
"name": key,
"value": key
});
}
commands.push(nwrplayCommand); commands.push(nwrplayCommand);
} }
await (async () => { await (async () => {
try { try {
//Global //Global
if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} Registering global commands: ${JSON.stringify(commands, null, 2)}`); if (config.debug >= 1) console.log(`${colors.magenta("[DEBUG]")} Registering global commands`);
await rest.put(Routes.applicationCommands(discord.user.id), { body: commands }) await rest.put(Routes.applicationCommands(discord.user.id), { body: commands })
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -763,21 +865,26 @@ discord.on("interactionCreate", async (interaction) => {
filterEvt = interaction.options.getString("filterevt") || null; filterEvt = interaction.options.getString("filterevt") || null;
message = interaction.options.getString("message") || null; message = interaction.options.getString("message") || null;
if (interaction.inGuild()) { if (interaction.inGuild()) {
db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => { interaction.channel.send("Permission check").then((msg) => {
if (err) { msg.delete();
console.error(err.message); db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => {
interaction.reply({ content: "Failed to subscribe to room", ephemeral: true });
} else if (row) {
return interaction.reply({ content: `Already subscribed to \`${getWFOByRoom(room).location}\`\nIf you want to update a subscribtion, please unsubscribe and resubscribe. This will be made a command eventually.`, ephemeral: true });
}
db.run(`INSERT INTO channels (channelid, iemchannel, custommessage, filter, filterevt, minPriority) VALUES (?, ?, ?, ? ,? ,?)`, [interaction.channel.id, room, message, filter, filterEvt, minPriority], (err) => {
if (err) { if (err) {
console.error(err.message); console.error(err.message);
interaction.reply({ content: "Failed to subscribe to room", ephemeral: true }); interaction.reply({ content: "Failed to subscribe to room", ephemeral: true });
} else { } else if (row) {
interaction.reply({ content: `Subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); return interaction.reply({ content: `Already subscribed to \`${getWFOByRoom(room).location}\`\nIf you want to update a subscribtion, please unsubscribe and resubscribe. This will be made a command eventually.`, ephemeral: true });
} }
db.run(`INSERT INTO channels (channelid, iemchannel, custommessage, filter, filterEvt, minPriority) VALUES (?, ?, ?, ? ,? ,?)`, [interaction.channel.id, room, message, filter, filterEvt, minPriority], (err) => {
if (err) {
console.error(err.message);
interaction.reply({ content: "Failed to subscribe to room", ephemeral: true });
} else {
interaction.reply({ content: `Subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true });
}
});
}); });
}).catch((err) => {
interaction.reply({ content: "Failed to subscribe to room. Bot does not have send message permissions here!", ephemeral: true });
}); });
} else { // We're in a DM } else { // We're in a DM
db.get(`SELECT * FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err, row) => { db.get(`SELECT * FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err, row) => {
@ -1248,48 +1355,42 @@ discord.on("interactionCreate", async (interaction) => {
console.error(err); console.error(err);
}); });
break; break;
case "sattelite": // Get satellite images case "satellite": // Get satellite images
sat = interaction.options.getString("sattelite"); sat = interaction.options.getString("satellite");
if (!sattelites[sat]) return interaction.reply({ content: "Invalid satellite", ephemeral: true }); if (!satellites[sat]) return interaction.reply({ content: "Invalid satellite", ephemeral: true });
// Fetch all the images // Fetch all the images
await interaction.deferReply(); productOptions = []
imageBuffers = {}; await (() => {
embeds = []; for (const key in satellites[sat].products) {
files = []; // make a discord customid safe id for the product name, add it to the satellites object
sattelites[sat].forEach(async (imgData) => { satellites[sat].products[key].customid = key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
// Get a buffer for the data, and put that in imageBuffers with the "name" as the key productOptions.push({
fetch(imgData.url).then((res) => { label: key,
if (res.status !== 200) { value: satellites[sat].products[key].customid
interaction.editReply({ content: "Failed to get satellite images", ephemeral: true }); })
return; }
} console.log(JSON.stringify(productOptions, null, 2))
res.buffer().then((buffer) => { })();
imageBuffers[imgData.name] = buffer; satMessages[interaction.id] = {
files.push({ sat
attachment: buffer, }
name: `${imgData.name}.jpg` await interaction.reply({
}); content: "Choose a product",
embeds.push({ components: [
title: `${sat} ${imgData.name}`, {
image: { type: 1,
url: `attachment://${imgData.name}.jpg` 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; break;
case "forecast": case "forecast":
@ -1310,51 +1411,198 @@ discord.on("interactionCreate", async (interaction) => {
} }
case Discord.InteractionType.MessageComponent: case Discord.InteractionType.MessageComponent:
if (interaction.customId) { if (!interaction.customId) return;
const product_id = interaction.customId; switch (interaction.customId.split("|")[0]) {
url = `https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id}`; case "product":
await interaction.deferReply({ ephemeral: true }); if (interaction.customId) {
fetch(url).then((res) => { const product_id = interaction.customId.split("|")[1];
if (res.status !== 200) { url = `https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id}`;
interaction.reply({ content: "Failed to get product text", ephemeral: true }); await interaction.deferReply({ ephemeral: true });
return; 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 break;
res.text().then(async (text) => { case "satproduct":
const pages = text.match(/[\s\S]{1,1900}(?=\n|$)/g); satData = satMessages[interaction.customId.split("|")[1]];
// const embeds = pages.map((page, ind) => ({ sat = satData.sat
// title: `Product Text for ${product_id} Pg ${ind + 1}/${pages.length}`, product = interaction.values[0];
// description: `\`\`\`${page}\`\`\``, // find the original product name
// color: 0x00ff00 product_name = Object.keys(satellites[sat].products).find(key => satellites[sat].products[key].customid === product);
// })); imageOptions = []
const messages = pages.map((page, ind) => { satMessages[interaction.customId.split("|")[1]] = {
return `\`\`\`${page}\`\`\`` sat,
}) product,
messages.forEach(async (message) => { product_name,
interaction.followUp({ content: message, ephemeral: true }); images: {}
}) }
await (() => {
// for key, value in satellites[sat].products[product_name]
console.log(product_name)
for (const key in satellites[sat].products[product_name]) {
// make a discord customid safe id for the product name, add it to the satellites object
//console.log(satellites[sat].products[product_name])
if (key === "customid") continue;
satMessages[interaction.customId.split("|")[1]].images[key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()] = satellites[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) => { break;
interaction.reply({ content: "Failed to get product text", ephemeral: true }); case "satproduct2":
console.log(`${colors.red("[ERROR]")} Failed to get product text: ${err.message}`); 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; break;
case Discord.InteractionType.ApplicationCommandAutocomplete:
//map nwrstreams
if (interaction.commandName === "nwrplay") {
let callsignSearch = interaction.options.getString("callsign");
let callsigns = Object.keys(nwrstreams.callsigns);
let results = callsigns.filter((callsign) => callsign.toLowerCase().includes(callsignSearch.toLowerCase()));
if (results.length > 25) {
results = results.slice(0, 25);
}
interaction.respond(results.map((callsign) => ({ name: callsign, value: callsign })));
}
break;
} }
}); });
discord.on("guildCreate", (guild) => { discord.on("guildCreate", async (guild) => {
let logs = await guild.fetchAuditLogs()
logs = logs.entries.filter(e => e.action === Discord.AuditLogEvent.BotAdd)
let user = logs.find(l => l.target?.id === discord.user.id)?.executor
// Get the main guild // Get the main guild
const myGuild = discord.guilds.cache.get(config.discord.mainGuild); const myGuild = discord.guilds.cache.get(config.discord.mainGuild);
// Get the log channel // Get the log channel
const channel = myGuild.channels.cache.get(config.discord.logChannel); const channel = myGuild.channels.cache.get(config.discord.logChannel);
// Send a message to the log channel // Send a message to the log channel
let invite = await discord.guilds.cache.get(config.discord.mainGuild).channels.cache.get(config.discord.inviteChannel).createInvite();
user.send({
embeds: [{
description: `Thanks for adding ${discord.user.username}!\nIf you have **ANY** questions, comments, suggestions, bug reports, etc, please feel free to throw it by us in our support server!\n\nTo get started use \`/subscribe\` to get alerts!`,
color: 0x00ff00
}],
components: [
{
type: Discord.ComponentType.ActionRow,
components: [
{
type: Discord.ComponentType.Button,
url: `https://discord.gg/${invite.code}`,
style: Discord.ButtonStyle.Link,
emoji: "",
label: "IEM Alerter Support Server"
}
]
}
]
}).catch((err) => {
console.log(`${colors.red("[ERROR]")} Failed to send message to user ${user.id}: ${err.message}`);
})
channel.send({ channel.send({
embeds: [ embeds: [
{ {
description: `I joined \`${guild.name}\``, description: `I joined \`${guild.name}\``,
fields: [
{
"name": "User",
"value": `<@${user.id}> (@${user.username}) ${user.displayName}`
}
],
color: 0x00ff00 color: 0x00ff00
} }
] ]
@ -1379,7 +1627,7 @@ discord.on("guildDelete", (guild) => {
}) })
process.on("unhandledRejection", (error, promise) => { 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 // create errors folder if it doesnt exist
if (!fs.existsSync("./error")) { if (!fs.existsSync("./error")) {
fs.mkdirSync("./error"); fs.mkdirSync("./error");
@ -1422,5 +1670,7 @@ process.on("uncaughtException", (error) => {
return; return;
}); });
// Login to discord // Login to discord
discord.login(config.discord.token); discord.login(config.discord.token);