diff --git a/README.md b/README.md index 3850a60..b9fe41c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # LiveMotdManager LiveMotdManager is a multi-platform Minecraft plugin that keeps your server list message dynamic. -It supports Spigot/Paper/Purpur/Folia servers and BungeeCord/Waterfall (1.16+) or Velocity proxies. +It supports Spigot/Paper/Purpur/Folia servers from 1.16 through 1.21 and BungeeCord/Waterfall (1.16+) or Velocity proxies. The MOTD can react to time of day, player counts, TPS, real world weather and Discord activity. ## Building @@ -36,8 +36,9 @@ See `config.yml` for an example configuration with multiple templates and integr ## Weather -Uses [open-meteo.com](https://open-meteo.com/) APIs with no key required. The plugin performs an -initial API test on startup and logs the result to the console. +Uses the [OpenWeather](https://openweathermap.org/) API. An API key is required and must be +specified in `weather.api-key` in the configuration. The plugin performs an initial API test on +startup and logs the result to the console. ## Discord diff --git a/bungee/src/main/resources/config.yml b/bungee/src/main/resources/config.yml index 46fea74..3dd5122 100644 --- a/bungee/src/main/resources/config.yml +++ b/bungee/src/main/resources/config.yml @@ -15,6 +15,8 @@ motd: weather: enable: true city: "Riga" + # Obtain a free API key from https://openweathermap.org/api + api-key: "" update-interval-minutes: 10 discord: diff --git a/config.yml b/config.yml index 46fea74..3dd5122 100644 --- a/config.yml +++ b/config.yml @@ -15,6 +15,8 @@ motd: weather: enable: true city: "Riga" + # Obtain a free API key from https://openweathermap.org/api + api-key: "" update-interval-minutes: 10 discord: diff --git a/core/src/main/java/com/livemotdmanager/core/MotdConfig.java b/core/src/main/java/com/livemotdmanager/core/MotdConfig.java index 73f65a4..152c5c3 100644 --- a/core/src/main/java/com/livemotdmanager/core/MotdConfig.java +++ b/core/src/main/java/com/livemotdmanager/core/MotdConfig.java @@ -20,6 +20,7 @@ public static class MotdRule { public static class WeatherSettings { public boolean enable = true; public String city = ""; + public String apiKey = ""; public int updateIntervalMinutes = 10; } diff --git a/core/src/main/java/com/livemotdmanager/core/WeatherService.java b/core/src/main/java/com/livemotdmanager/core/WeatherService.java index 2d2c3f5..e866a11 100644 --- a/core/src/main/java/com/livemotdmanager/core/WeatherService.java +++ b/core/src/main/java/com/livemotdmanager/core/WeatherService.java @@ -10,16 +10,18 @@ import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Locale; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** - * Fetches real world weather information using open-meteo.com. + * Fetches real world weather information using the OpenWeather API. */ public class WeatherService { private final boolean enabled; private final String city; + private final String apiKey; private final int updateIntervalMinutes; private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); private volatile String cached = ""; @@ -28,6 +30,7 @@ public class WeatherService { public WeatherService(MotdConfig.WeatherSettings settings) { this.enabled = settings.enable; this.city = settings.city; + this.apiKey = settings.apiKey; this.updateIntervalMinutes = settings.updateIntervalMinutes; } @@ -48,49 +51,24 @@ public String getCachedWeather() { } private void update() { - if (!enabled || city == null || city.isEmpty()) return; + if (!enabled || city == null || city.isEmpty() || apiKey == null || apiKey.isEmpty()) return; try { - // Geocode city (encode to handle spaces and special characters) String encodedCity = URLEncoder.encode(city, StandardCharsets.UTF_8); - String geocodeUrl = String.format("https://geocoding-api.open-meteo.com/v1/search?count=1&name=%s", encodedCity); - HttpRequest geoReq = HttpRequest.newBuilder().uri(URI.create(geocodeUrl)).timeout(Duration.ofSeconds(10)).build(); - HttpResponse geoResp = http.send(geoReq, HttpResponse.BodyHandlers.ofString()); - JsonObject geoJson = JsonParser.parseString(geoResp.body()).getAsJsonObject(); - if (!geoJson.has("results")) return; - JsonObject first = geoJson.getAsJsonArray("results").get(0).getAsJsonObject(); - double lat = first.get("latitude").getAsDouble(); - double lon = first.get("longitude").getAsDouble(); - - String weatherUrl = String.format("https://api.open-meteo.com/v1/forecast?latitude=%f&longitude=%f¤t_weather=true", lat, lon); - HttpRequest weatherReq = HttpRequest.newBuilder().uri(URI.create(weatherUrl)).timeout(Duration.ofSeconds(10)).build(); - HttpResponse weatherResp = http.send(weatherReq, HttpResponse.BodyHandlers.ofString()); - JsonObject weatherJson = JsonParser.parseString(weatherResp.body()).getAsJsonObject(); - if (!weatherJson.has("current_weather")) return; - JsonObject cur = weatherJson.getAsJsonObject("current_weather"); - double temp = cur.get("temperature").getAsDouble(); - int code = cur.get("weathercode").getAsInt(); - String desc = WeatherCode.describe(code); - cached = String.format("%s %.1f°C", desc, temp); + String url = String.format("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric", encodedCity, apiKey); + HttpRequest req = HttpRequest.newBuilder().uri(URI.create(url)).timeout(Duration.ofSeconds(10)).build(); + HttpResponse resp = http.send(req, HttpResponse.BodyHandlers.ofString()); + JsonObject json = JsonParser.parseString(resp.body()).getAsJsonObject(); + if (!json.has("weather") || !json.has("main")) return; + JsonObject main = json.getAsJsonObject("main"); + double temp = main.get("temp").getAsDouble(); + JsonObject first = json.getAsJsonArray("weather").get(0).getAsJsonObject(); + String desc = first.get("description").getAsString(); + if (!desc.isEmpty()) { + desc = desc.substring(0,1).toUpperCase(Locale.ROOT) + desc.substring(1); + } + cached = String.format(Locale.US, "%s %.1f°C", desc, temp); } catch (Exception e) { // ignore but keep cached } } - - /** - * Maps open-meteo weather codes to short descriptions. - */ - public static class WeatherCode { - public static String describe(int code) { - switch (code) { - case 0: return "Clear"; - case 1: case 2: case 3: return "Cloudy"; - case 45: case 48: return "Fog"; - case 51: case 53: case 55: return "Drizzle"; - case 61: case 63: case 65: return "Rain"; - case 71: case 73: case 75: return "Snow"; - case 95: return "Thunder"; - default: return "Weather"; - } - } - } } diff --git a/spigot/pom.xml b/spigot/pom.xml index 94aab69..50b49d7 100644 --- a/spigot/pom.xml +++ b/spigot/pom.xml @@ -21,7 +21,7 @@ org.spigotmc spigot-api - 1.20.1-R0.1-SNAPSHOT + 1.16.5-R0.1-SNAPSHOT provided diff --git a/spigot/src/main/resources/config.yml b/spigot/src/main/resources/config.yml index 46fea74..3dd5122 100644 --- a/spigot/src/main/resources/config.yml +++ b/spigot/src/main/resources/config.yml @@ -15,6 +15,8 @@ motd: weather: enable: true city: "Riga" + # Obtain a free API key from https://openweathermap.org/api + api-key: "" update-interval-minutes: 10 discord: diff --git a/velocity/src/main/resources/config.yml b/velocity/src/main/resources/config.yml index 46fea74..3dd5122 100644 --- a/velocity/src/main/resources/config.yml +++ b/velocity/src/main/resources/config.yml @@ -15,6 +15,8 @@ motd: weather: enable: true city: "Riga" + # Obtain a free API key from https://openweathermap.org/api + api-key: "" update-interval-minutes: 10 discord: