diff --git a/README.md b/README.md index dced7486..d96d1907 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,7 @@ bitsadmin /transfer dotnet-install-job /download /priority FOREGROUND https://ra 8.) Build executable `dotnet build ../../..` (if dotnet is in your path) otherwise `~/.dotnet/dotnet build ../../..` 9.) Start WhMgr `dotnet WhMgr.dll` (if dotnet is in your path) otherwise `~/.dotnet/dotnet WhMgr.dll` (If Windows, run as Administrator) 10.) Optional User Interface for members to create subscriptions from a website instead of using Discord commands. (Still WIP but mostly done) [WhMgr UI](https://github.com/versx/WhMgr-UI) +11.) Optional reverse location lookup with OpenStreetMaps Nominatim instead of Google Maps, install instructions [here](https://nominatim.org/release-docs/develop/admin/Installation/) ## Updating 1.) Pull latest changes in root folder diff --git a/config.example.json b/config.example.json index d605643d..1c8550a6 100644 --- a/config.example.json +++ b/config.example.json @@ -141,6 +141,7 @@ "minIV": 100 }, "gmapsKey": "", + "nominatim": "https://nominatim.openstreetmap.org", "despawnTimeMinimumMinutes": 5, "reloadSubscriptionChangesMinutes": 1, "debug": false, diff --git a/src/Commands/Nests.cs b/src/Commands/Nests.cs index 528e2d4b..728c6fbe 100644 --- a/src/Commands/Nests.cs +++ b/src/Commands/Nests.cs @@ -145,7 +145,15 @@ public IReadOnlyDictionary GetProperties(DiscordGuild guild, Nes var geofences = _dep.Whm.Geofences.Values.ToList(); var geofence = GeofenceService.GetGeofence(geofences, new Location(nest.Latitude, nest.Longitude)); var city = geofence?.Name ?? "Unknown"; - var googleAddress = Utils.GetGoogleAddress(city, nest.Latitude, nest.Longitude, _dep.WhConfig.GoogleMapsKey); + Location address; + if (!string.IsNullOrEmpty(_dep.WhConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, nest.Latitude, nest.Longitude, _dep.WhConfig.GoogleMapsKey); + } + else + { + address = Utils.GetNominatimAddress(city, nest.Latitude, nest.Longitude, _dep.WhConfig.NominatimEndpoint); + } var dict = new Dictionary { @@ -177,7 +185,7 @@ public IReadOnlyDictionary GetProperties(DiscordGuild guild, Nes { "wazemaps_url", wazeMapsLink }, { "scanmaps_url", scannerMapsLink }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, // Discord Guild properties { "guild_name", guild?.Name }, diff --git a/src/Configuration/WhConfig.cs b/src/Configuration/WhConfig.cs index d7be453a..d3ea09fa 100644 --- a/src/Configuration/WhConfig.cs +++ b/src/Configuration/WhConfig.cs @@ -92,6 +92,12 @@ public class WhConfig [JsonProperty("gmapsKey")] public string GoogleMapsKey { get; set; } + /// + /// Gets or sets the OpenStreetMaps Nominatim endpoint to use for reverse location lookup + /// + [JsonProperty("nominatim")] + public string NominatimEndpoint { get; set; } + /// /// Gets or sets the minimum despawn time in minutes a Pokemon must have in order to send the alarm /// diff --git a/src/Net/Models/GymDetailsData.cs b/src/Net/Models/GymDetailsData.cs index e4cf8585..6afa5002 100644 --- a/src/Net/Models/GymDetailsData.cs +++ b/src/Net/Models/GymDetailsData.cs @@ -144,7 +144,15 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh var appleMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? appleMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, appleMapsLink); var wazeMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? wazeMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, wazeMapsLink); var scannerMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? scannerMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, scannerMapsLink); - var googleAddress = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + Geofence.Location address = null; + if (!string.IsNullOrEmpty(whConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + } + else if (!string.IsNullOrEmpty(whConfig.NominatimEndpoint)) + { + address = Utils.GetNominatimAddress(city, Latitude, Longitude, whConfig.NominatimEndpoint); + } //var staticMapLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? staticMapLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, staticMapLink); const string defaultMissingValue = "?"; @@ -185,7 +193,7 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh { "wazemaps_url", wazeMapsLocationLink }, { "scanmaps_url", scannerMapsLocationLink }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, // Discord Guild properties { "guild_name", guild?.Name }, diff --git a/src/Net/Models/PokemonData.cs b/src/Net/Models/PokemonData.cs index fd8ef47a..3bc3677b 100644 --- a/src/Net/Models/PokemonData.cs +++ b/src/Net/Models/PokemonData.cs @@ -478,7 +478,15 @@ private async Task> GetProperties(DiscordGui var appleMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? appleMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, appleMapsLink); var wazeMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? wazeMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, wazeMapsLink); var scannerMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? scannerMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, scannerMapsLink); - var googleAddress = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + Geofence.Location address = null; + if (!string.IsNullOrEmpty(whConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + } + else if (!string.IsNullOrEmpty(whConfig.NominatimEndpoint)) + { + address = Utils.GetNominatimAddress(city, Latitude, Longitude, whConfig.NominatimEndpoint); + } //var staticMapLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? staticMapLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, staticMapLink); var pokestop = Pokestop.Pokestops.ContainsKey(PokestopId) ? Pokestop.Pokestops[PokestopId] : null; @@ -579,7 +587,7 @@ private async Task> GetProperties(DiscordGui { "wazemaps_url", wazeMapsLocationLink }, { "scanmaps_url", scannerMapsLocationLink }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, // Pokestop properties { "near_pokestop", Convert.ToString(pokestop != null) }, diff --git a/src/Net/Models/PokestopData.cs b/src/Net/Models/PokestopData.cs index 631af16b..b202ad0a 100644 --- a/src/Net/Models/PokestopData.cs +++ b/src/Net/Models/PokestopData.cs @@ -155,7 +155,15 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh var appleMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? appleMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, appleMapsLink); var wazeMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? wazeMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, wazeMapsLink); var scannerMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? scannerMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, scannerMapsLink); - var googleAddress = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + Geofence.Location address = null; + if (!string.IsNullOrEmpty(whConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + } + else if (!string.IsNullOrEmpty(whConfig.NominatimEndpoint)) + { + address = Utils.GetNominatimAddress(city, Latitude, Longitude, whConfig.NominatimEndpoint); + } //var staticMapLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? staticMapLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, staticMapLink); var invasion = MasterFile.Instance.GruntTypes.ContainsKey(GruntType) ? MasterFile.Instance.GruntTypes[GruntType] : null; var leaderString = Translator.Instance.Translate("grunt_" + Convert.ToInt32(GruntType)); @@ -204,7 +212,7 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh { "lure_img_url", lureImageUrl }, { "invasion_img_url", invasionImageUrl }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, // Discord Guild properties { "guild_name", guild?.Name }, diff --git a/src/Net/Models/QuestData.cs b/src/Net/Models/QuestData.cs index 3e413034..15764659 100644 --- a/src/Net/Models/QuestData.cs +++ b/src/Net/Models/QuestData.cs @@ -119,7 +119,15 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh var appleMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? appleMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, appleMapsLink); var wazeMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? wazeMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, wazeMapsLink); var scannerMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? scannerMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, scannerMapsLink); - var googleAddress = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + Geofence.Location address = null; + if (!string.IsNullOrEmpty(whConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + } + else if (!string.IsNullOrEmpty(whConfig.NominatimEndpoint)) + { + address = Utils.GetNominatimAddress(city, Latitude, Longitude, whConfig.NominatimEndpoint); + } //var staticMapLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? staticMapLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, staticMapLink); const string defaultMissingValue = "?"; @@ -148,7 +156,7 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh { "wazemaps_url", wazeMapsLocationLink }, { "scanmaps_url", scannerMapsLocationLink }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, //Pokestop properties { "pokestop_id", PokestopId ?? defaultMissingValue }, diff --git a/src/Net/Models/RaidData.cs b/src/Net/Models/RaidData.cs index 471a2322..32671a2f 100644 --- a/src/Net/Models/RaidData.cs +++ b/src/Net/Models/RaidData.cs @@ -211,7 +211,15 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh var appleMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? appleMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, appleMapsLink); var wazeMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? wazeMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, wazeMapsLink); var scannerMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? scannerMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, scannerMapsLink); - var googleAddress = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + Geofence.Location address = null; + if (!string.IsNullOrEmpty(whConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + } + else if (!string.IsNullOrEmpty(whConfig.NominatimEndpoint)) + { + address = Utils.GetNominatimAddress(city, Latitude, Longitude, whConfig.NominatimEndpoint); + } //var staticMapLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? staticMapLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, staticMapLink); const string defaultMissingValue = "?"; @@ -275,7 +283,7 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh { "wazemaps_url", wazeMapsLocationLink }, { "scanmaps_url", scannerMapsLocationLink }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, //Gym properties { "gym_id", GymId }, diff --git a/src/Net/Models/WeatherData.cs b/src/Net/Models/WeatherData.cs index 5aa115b6..5e418aad 100644 --- a/src/Net/Models/WeatherData.cs +++ b/src/Net/Models/WeatherData.cs @@ -134,6 +134,10 @@ public DiscordEmbedNotification GenerateWeatherMessage(ulong guildId, DiscordCli return new DiscordEmbedNotification(username, iconUrl, description, new List { eb.Build() }); } + #endregion + + #region Private Methods + private IReadOnlyDictionary GetProperties(DiscordGuild guild, WhConfig whConfig, string city, string weatherImageUrl) { var weather = Translator.Instance.GetWeather(GameplayCondition); @@ -150,7 +154,15 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh var appleMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? appleMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, appleMapsLink); var wazeMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? wazeMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, wazeMapsLink); var scannerMapsLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? scannerMapsLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, scannerMapsLink); - var googleAddress = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + Geofence.Location address = null; + if (!string.IsNullOrEmpty(whConfig.GoogleMapsKey)) + { + address = Utils.GetGoogleAddress(city, Latitude, Longitude, whConfig.GoogleMapsKey); + } + else if (!string.IsNullOrEmpty(whConfig.NominatimEndpoint)) + { + address = Utils.GetNominatimAddress(city, Latitude, Longitude, whConfig.NominatimEndpoint); + } //var staticMapLocationLink = string.IsNullOrEmpty(whConfig.ShortUrlApiUrl) ? staticMapLink : NetUtil.CreateShortUrl(whConfig.ShortUrlApiUrl, staticMapLink); const string defaultMissingValue = "?"; @@ -188,7 +200,7 @@ private IReadOnlyDictionary GetProperties(DiscordGuild guild, Wh { "wazemaps_url", wazeMapsLocationLink }, { "scanmaps_url", scannerMapsLocationLink }, - { "address", googleAddress?.Address }, + { "address", address?.Address }, // Discord Guild properties { "guild_name", guild?.Name }, diff --git a/src/Utilities/Utils.cs b/src/Utilities/Utils.cs index 03ae81c2..d5f4e5af 100644 --- a/src/Utilities/Utils.cs +++ b/src/Utilities/Utils.cs @@ -110,5 +110,27 @@ public static Location GetGoogleAddress(string city, double lat, double lng, str } return null; } + + public static Location GetNominatimAddress(string city, double lat, double lng, string endpoint) + { + var unknown = "Unknown"; + var url = $"{endpoint}/reverse?format=jsonv2&lat={lat}&lon={lng}"; + try + { + using (var wc = new WebClient()) + { + wc.Proxy = null; + wc.Headers.Add("User-Agent", Strings.BotName); + var json = wc.DownloadString(url); + dynamic obj = JsonConvert.DeserializeObject(json); + return new Location(Convert.ToString(obj.display_name), city ?? unknown, Convert.ToDouble(obj.lat), Convert.ToDouble(obj.lon)); + } + } + catch (Exception ex) + { + _logger.Error(ex); + } + return null; + } } } \ No newline at end of file