forked from ChrisChrome/weather-bot
136 lines
3.2 KiB
JavaScript
136 lines
3.2 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, 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, 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];
|
|
console.log(period.icon)
|
|
const embed = {
|
|
title: `${period.name} in ${forecastData.properties.relativeLocation.properties.city} ${forecastData.properties.relativeLocation.properties.state}`,
|
|
description: 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'
|
|
}
|
|
};
|
|
embeds.push(embed);
|
|
}
|
|
return embeds;
|
|
}
|
|
|
|
|
|
module.exports = {
|
|
getCoordinates,
|
|
getForecast,
|
|
getWeatherBySearch,
|
|
generateDiscordEmbeds
|
|
}; |