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",
"zdcchat@conference.weather.im",
"znychat@conference.weather.im"
]

View file

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

View file

@ -1,13 +1,13 @@
{
"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",
"https://www.spc.noaa.gov/products/exper/day4-8/day4prob.gif",
"https://www.spc.noaa.gov/products/exper/day4-8/day5prob.gif",
"https://www.spc.noaa.gov/products/exper/day4-8/day6prob.gif",
"https://www.spc.noaa.gov/products/exper/day4-8/day7prob.gif",
"https://www.spc.noaa.gov/products/exper/day4-8/day8prob.gif"
"https://weather.cod.edu/cdata/text/images/spc/co/day1/categorical/spccoday1.categorical.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day2/categorical/spccoday2.categorical.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day3/categorical/spccoday3.categorical.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day4/severe/spccoday4.severe.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day5/severe/spccoday5.severe.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day6/severe/spccoday6.severe.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day7/severe/spccoday7.severe.latest.png",
"https://climate.cod.edu/data/text/images/spc/co/day8/severe/spccoday8.severe.latest.png"
],
"fire": [
"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"
}
]
}

380
index.js
View file

@ -6,8 +6,8 @@ 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 sattelites = require("./data/sattelites.json");
const nwrstreams = require("./data/nwrstreams.json")
const satellites = require("./data/satellites.json");
const nwrstreams = {callsigns:{}};
const Jimp = require("jimp");
const { client, xml } = require("@xmpp/client");
const fetch = require("node-fetch");
@ -16,8 +16,12 @@ 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: [
"Guilds",
"GuildVoiceStates",
@ -32,7 +36,6 @@ const rest = new REST({
version: '10'
}).setToken(config.discord.token);
// Setup SQlite DB
const db = new sqlite3.Database("channels.db", (err) => {
if (err) {
@ -40,8 +43,9 @@ const db = new sqlite3.Database("channels.db", (err) => {
}
console.log(`${colors.cyan("[INFO]")} Connected to the database`);
// 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(`ALTER TABLE channels RENAME COLUMN filterevt TO filterEvt;`)
});
@ -260,6 +264,24 @@ var errCount = 0;
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({
service: "xmpp://conference.weather.im",
domain: "weather.im",
@ -286,6 +308,8 @@ xmpp.on("offline", () => {
})
});
var restartTimer = null;
xmpp.on("stanza", (stanza) => {
// Debug stuff
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
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
if (startup) return;
// Get channel name
@ -331,6 +360,16 @@ xmpp.on("stanza", (stanza) => {
evt = { name: "Unknown", priority: 3 }
console.log(`${colors.red("[ERROR]")} Unknown event type: ${product_id.pil.substring(0, 3)}. Fix me`);
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);
@ -338,13 +377,14 @@ xmpp.on("stanza", (stanza) => {
const now = new Date();
const diff = (now - product_id.timestamp) / 1000 / 60;
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++;
// Handle NTFY
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 = {
"topic": `${config.ntfy.prefix}${fromChannel}`,
"message": bodyData.string,
@ -362,7 +402,7 @@ xmpp.on("stanza", (stanza) => {
'Authorization': `Bearer ${config.ntfy.token}`
}
}).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}`);
@ -402,7 +442,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: "📄"
@ -418,7 +458,7 @@ xmpp.on("stanza", (stanza) => {
console.log(`${colors.red("[ERROR]")} ${err.message}`);
}
if (!rows) return; // No channels to alert
rows.forEach((row) => {
rows.forEach(async (row) => {
// Get Filters as arrays
if (!row.filterEvt) row.filterEvt = "";
if (!row.filter) row.filter = "";
@ -444,6 +484,54 @@ xmpp.on("stanza", (stanza) => {
console.error(err);
}).then((msg) => {
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) => {
@ -489,6 +577,27 @@ xmpp.on("stanza", (stanza) => {
thisMsg.content = row.custommessage || null;
user.send(thisMsg).catch((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) => {
@ -595,20 +704,19 @@ discord.on('ready', async () => {
commands = require("./data/commands.json");
// Add dynamic commands (based on datas files)
satCommand = {
"name": "sattelite",
"description": "Get the latest sattelite images from a given sattelite",
"name": "satellite",
"description": "Get the latest satellite images from a given satellite",
"options": [
{
"name": "sattelite",
"description": "The sattelite to get images from",
"name": "satellite",
"description": "The satellite to get images from",
"type": 3,
"required": true,
"choices": []
}
]
}
for (const key in sattelites) {
// Push the key to the choices array
for (const key in satellites) {
satCommand.options[0].choices.push({
"name": key,
"value": key
@ -683,22 +791,16 @@ discord.on('ready', async () => {
"description": "The URL of the stream to play",
"type": 3,
"required": true,
"choices": []
"autocomplete": true
}
]
}
for (const key in nwrstreams.callsigns) {
nwrplayCommand.options[0].choices.push({
"name": key,
"value": key
});
}
commands.push(nwrplayCommand);
}
await (async () => {
try {
//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 })
} catch (error) {
console.error(error);
@ -763,6 +865,8 @@ discord.on("interactionCreate", async (interaction) => {
filterEvt = interaction.options.getString("filterevt") || null;
message = interaction.options.getString("message") || null;
if (interaction.inGuild()) {
interaction.channel.send("Permission check").then((msg) => {
msg.delete();
db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => {
if (err) {
console.error(err.message);
@ -770,7 +874,7 @@ discord.on("interactionCreate", async (interaction) => {
} 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) => {
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 });
@ -779,6 +883,9 @@ discord.on("interactionCreate", async (interaction) => {
}
});
});
}).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
db.get(`SELECT * FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err, row) => {
if (err) {
@ -1248,48 +1355,42 @@ discord.on("interactionCreate", async (interaction) => {
console.error(err);
});
break;
case "sattelite": // Get satellite images
sat = interaction.options.getString("sattelite");
if (!sattelites[sat]) return interaction.reply({ content: "Invalid satellite", ephemeral: true });
case "satellite": // Get satellite images
sat = interaction.options.getString("satellite");
if (!satellites[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;
productOptions = []
await (() => {
for (const key in satellites[sat].products) {
// make a discord customid safe id for the product name, add it to the satellites object
satellites[sat].products[key].customid = key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
productOptions.push({
label: key,
value: satellites[sat].products[key].customid
})
}
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`
console.log(JSON.stringify(productOptions, null, 2))
})();
satMessages[interaction.id] = {
sat
}
});
// Check if we have all the images
if (Object.keys(imageBuffers).length === sattelites[sat].length) {
// Send the images
interaction.editReply({
embeds,
files
});
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
}
});
}).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,8 +1411,11 @@ discord.on("interactionCreate", async (interaction) => {
}
case Discord.InteractionType.MessageComponent:
if (!interaction.customId) return;
switch (interaction.customId.split("|")[0]) {
case "product":
if (interaction.customId) {
const product_id = 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) => {
@ -1340,21 +1444,165 @@ discord.on("interactionCreate", async (interaction) => {
});
}
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(satellites[sat].products).find(key => satellites[sat].products[key].customid === product);
imageOptions = []
satMessages[interaction.customId.split("|")[1]] = {
sat,
product,
product_name,
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();
});
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;
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
const myGuild = discord.guilds.cache.get(config.discord.mainGuild);
// Get the log channel
const channel = myGuild.channels.cache.get(config.discord.logChannel);
// 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({
embeds: [
{
description: `I joined \`${guild.name}\``,
fields: [
{
"name": "User",
"value": `<@${user.id}> (@${user.username}) ${user.displayName}`
}
],
color: 0x00ff00
}
]
@ -1379,7 +1627,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");
@ -1422,5 +1670,7 @@ process.on("uncaughtException", (error) => {
return;
});
// Login to discord
discord.login(config.discord.token);