weather-bot/funcs.js
2024-06-20 18:11:15 -06:00

138 lines
3.5 KiB
JavaScript

const geolib = require("geolib");
// Use OSM API to get coordinates https://nominatim.openstreetmap.org/search?q=search+query&format=json&limit=1
const getCoordinates = async (location) => {
return new Promise((resolve, reject) => {
// Make location url friendly
location = encodeURIComponent(location);
const url = `https://nominatim.openstreetmap.org/search?q=${location}&format=json&limit=1`;
// use custom useragent (discord-iem-bot, chris@chrischro.me)
const options = {
headers: {
'User-Agent': 'Discord-IEM-Bot/1.0 (chris@chrischro.me)',
},
};
// Make request
fetch(url, options)
.then(response => response.json())
.then(data => {
if (data.length > 0) {
resolve({
lat: data[0].lat,
lon: data[0].lon,
});
} else {
reject('Location not found');
}
})
.catch(err => {
reject(err);
});
})
};
const getForecast = async (lat, lon) => {
return new Promise((resolve, reject) => {
const url = `https://api.weather.gov/points/${lat},${lon}`;
// use same custom ua
const options = {
headers: {
'User-Agent': 'Discord-IEM-Bot/1.0 (chris@chrischro.me)',
},
};
// Make request
fetch(url, options)
.then(response => response.json())
.then(data => {
if (data.properties?.forecast) {
fetch(data.properties.forecast)
.then(response => response.json())
.then(data2 => {
data2.properties.relativeLocation = data.properties.relativeLocation;
resolve(data2);
})
.catch(err => {
reject(err);
});
} else {
reject('Forecast not found');
}
})
.catch(err => {
reject(err);
});
})
};
const getWeatherBySearch = async (search) => {
return new Promise((resolve, reject) => {
getCoordinates(search)
.then(coords => {
getForecast(coords.lat, coords.lon)
.then(data => {
resolve(data);
})
.catch(err => {
reject(err);
});
})
.catch(err => {
reject(err);
});
})
};
const generateDiscordEmbeds = (forecastData, numOfDays) => {
// Take the first 7 periods and make them into embeds
const embeds = [];
if (!numOfDays) numOfDays = 1;
for (let i = 0; i < numOfDays; i++) {
const period = forecastData.properties.periods[i];
if (period.icon?.startsWith("/")) {
period.icon = `https://api.weather.gov${period.icon}`
}
const embed = {
title: `${period.name} in ${forecastData.properties.relativeLocation.properties.city} ${forecastData.properties.relativeLocation.properties.state}`,
description: `Valid <t:${new Date(period.startTime)/1000}:f> - <t:${new Date(period.endTime)/1000}:f>\n${period.detailedForecast}`,
timestamp: new Date(period.startTime),
thumbnail: {
url: period.icon,
},
fields: [
{
name: 'Temperature',
value: `${period.temperature}°F`,
inline: true
},
{
name: 'Wind',
value: `${period.windDirection}@${period.windSpeed}`,
inline: true
},
{
name: 'Precipitation',
value: period.probabilityOfPrecipitation?.value ? period.probabilityOfPrecipitation?.value + '%' : '0%',
inline: true
},
{
name: 'Humidity',
value: period.relativeHumidity?.value ? period.relativeHumidity.value + '%' : "0%",
}
],
footer: {
text: `Data provided by the National Weather Service · Elevation ${forecastData.properties.elevation.value}m`
}
};
embeds.push(embed);
}
return embeds;
}
module.exports = {
getCoordinates,
getForecast,
getWeatherBySearch,
generateDiscordEmbeds
};