diff --git a/Nettify.Demo/Fixtures/Cases/Forecast.cs b/Nettify.Demo/Fixtures/Cases/Forecast.cs
index 2b2d5c1..abbd7c2 100644
--- a/Nettify.Demo/Fixtures/Cases/Forecast.cs
+++ b/Nettify.Demo/Fixtures/Cases/Forecast.cs
@@ -28,32 +28,25 @@ internal class Forecast : IFixture
public void RunFixture()
{
string ApiKey;
- string StringID;
+ double latitude, longitude;
WeatherForecastInfo forecastInfo;
- bool IsNumeric;
// ID or name
- Console.Write("Enter city ID or name: ");
- StringID = Console.ReadLine();
- IsNumeric = long.TryParse(StringID, out long FinalID);
+ Console.Write("Enter city latitude: ");
+ latitude = double.Parse(Console.ReadLine());
+ Console.Write("Enter city longitude: ");
+ longitude = double.Parse(Console.ReadLine());
// API key
- Console.Write("Enter API key: ");
+ Console.Write("Enter TWC API key: ");
ApiKey = Console.ReadLine();
// Get weather info
- if (IsNumeric)
- forecastInfo = WeatherForecast.GetWeatherInfo(FinalID, ApiKey, UnitMeasurement.Metric);
- else
- forecastInfo = WeatherForecast.GetWeatherInfo(StringID, ApiKey, UnitMeasurement.Metric);
+ forecastInfo = WeatherForecast.GetWeatherInfo(latitude, longitude, ApiKey, UnitMeasurement.Metric);
// Print the weather information
- Console.WriteLine("City ID: " + forecastInfo.CityID);
- Console.WriteLine("City Name: " + forecastInfo.CityName);
Console.WriteLine("Weather State: " + forecastInfo.Weather);
Console.WriteLine("Temperature: " + forecastInfo.Temperature);
- Console.WriteLine("Feels Like: " + forecastInfo.FeelsLike);
- Console.WriteLine("Pressure: " + forecastInfo.Pressure);
Console.WriteLine("Humidity: " + forecastInfo.Humidity);
Console.WriteLine("Wind Speed: " + forecastInfo.WindSpeed);
Console.WriteLine("Wind Direction: " + forecastInfo.WindDirection);
diff --git a/Nettify.Demo/Fixtures/Cases/ForecastList.cs b/Nettify.Demo/Fixtures/Cases/ForecastList.cs
new file mode 100644
index 0000000..5434bd4
--- /dev/null
+++ b/Nettify.Demo/Fixtures/Cases/ForecastList.cs
@@ -0,0 +1,48 @@
+//
+// Nettify Copyright (C) 2023-2024 Aptivi
+//
+// This file is part of Nettify
+//
+// Nettify is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Nettify is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY, without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using Nettify.Weather;
+using System;
+
+namespace Nettify.Demo.Fixtures.Cases
+{
+ internal class ForecastList : IFixture
+ {
+ public string FixtureID => "ForecastList";
+ public void RunFixture()
+ {
+ // City
+ Console.Write("Enter city name: ");
+ string city = Console.ReadLine();
+
+ // API key
+ Console.Write("Enter TWC API key: ");
+ string ApiKey = Console.ReadLine();
+
+ // List all cities
+ var longsLats = WeatherForecast.ListAllCities(city, ApiKey);
+ foreach (var longLat in longsLats)
+ {
+ string name = longLat.Key;
+ (double latitude, double longitude) = longLat.Value;
+ Console.WriteLine($"Name: {name,-55}\t\tlat: {latitude,-10}\tlng: {longitude,-10}");
+ }
+ }
+ }
+}
diff --git a/Nettify.Demo/Fixtures/Cases/ForecastOwm.cs b/Nettify.Demo/Fixtures/Cases/ForecastOwm.cs
new file mode 100644
index 0000000..02e96a1
--- /dev/null
+++ b/Nettify.Demo/Fixtures/Cases/ForecastOwm.cs
@@ -0,0 +1,58 @@
+//
+// Nettify Copyright (C) 2023-2024 Aptivi
+//
+// This file is part of Nettify
+//
+// Nettify is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Nettify is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY, without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using Nettify.Weather;
+using System;
+
+namespace Nettify.Demo.Fixtures.Cases
+{
+ internal class ForecastOwm : IFixture
+ {
+ public string FixtureID => "ForecastOwm";
+ public void RunFixture()
+ {
+ string ApiKey;
+ string StringID;
+ WeatherForecastInfo forecastInfo;
+ bool IsNumeric;
+
+ // ID or name
+ Console.Write("Enter city ID or name: ");
+ StringID = Console.ReadLine();
+ IsNumeric = long.TryParse(StringID, out long FinalID);
+
+ // API key
+ Console.Write("Enter API key: ");
+ ApiKey = Console.ReadLine();
+
+ // Get weather info
+ if (IsNumeric)
+ forecastInfo = WeatherForecastOwm.GetWeatherInfo(FinalID, ApiKey, UnitMeasurement.Metric);
+ else
+ forecastInfo = WeatherForecastOwm.GetWeatherInfo(StringID, ApiKey, UnitMeasurement.Metric);
+
+ // Print the weather information
+ Console.WriteLine("Weather State: " + forecastInfo.Weather);
+ Console.WriteLine("Temperature: " + forecastInfo.Temperature);
+ Console.WriteLine("Humidity: " + forecastInfo.Humidity);
+ Console.WriteLine("Wind Speed: " + forecastInfo.WindSpeed);
+ Console.WriteLine("Wind Direction: " + forecastInfo.WindDirection);
+ }
+ }
+}
diff --git a/Nettify.Demo/Fixtures/FixtureManager.cs b/Nettify.Demo/Fixtures/FixtureManager.cs
index 91e90c0..fa501c9 100644
--- a/Nettify.Demo/Fixtures/FixtureManager.cs
+++ b/Nettify.Demo/Fixtures/FixtureManager.cs
@@ -34,6 +34,8 @@ internal static class FixtureManager
new Dictionary(),
// Forecast
+ new ForecastOwm(),
+ new ForecastList(),
new Forecast(),
// RSS
diff --git a/Nettify.Demo/Properties/launchSettings.json b/Nettify.Demo/Properties/launchSettings.json
index 15b0734..e546dcd 100644
--- a/Nettify.Demo/Properties/launchSettings.json
+++ b/Nettify.Demo/Properties/launchSettings.json
@@ -16,6 +16,14 @@
"commandName": "Project",
"commandLineArgs": "Forecast"
},
+ "Nettify.Demo - ForecastOwm": {
+ "commandName": "Project",
+ "commandLineArgs": "ForecastOwm"
+ },
+ "Nettify.Demo - ForecastList": {
+ "commandName": "Project",
+ "commandLineArgs": "ForecastList"
+ },
"Nettify.Demo - RssFeedViewer": {
"commandName": "Project",
"commandLineArgs": "RssFeedViewer"
diff --git a/Nettify/Weather/WeatherForecast.cs b/Nettify/Weather/WeatherForecast.cs
index 1529a71..75bb083 100644
--- a/Nettify/Weather/WeatherForecast.cs
+++ b/Nettify/Weather/WeatherForecast.cs
@@ -17,6 +17,7 @@
// along with this program. If not, see .
//
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -29,40 +30,28 @@
namespace Nettify.Weather
{
///
- /// The forecast tools
+ /// The forecast tools (The Weather Channel)
///
public static class WeatherForecast
{
internal static HttpClient WeatherDownloader = new();
///
- /// Gets current weather info from OpenWeatherMap
+ /// Gets current weather info from The Weather Channel
///
- /// City ID
- /// API key
- /// The preferred unit to use
- /// A class containing properties of weather information
- public static WeatherForecastInfo GetWeatherInfo(long CityID, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
- {
- string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?id={CityID}&appid={APIKey}";
- return GetWeatherInfo(WeatherURL, Unit);
- }
-
- ///
- /// Gets current weather info from OpenWeatherMap
- ///
- /// City name
+ /// City latitude
+ /// City longitude
/// API Key
/// The preferred unit to use
/// A class containing properties of weather information
- public static WeatherForecastInfo GetWeatherInfo(string CityName, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
+ public static WeatherForecastInfo GetWeatherInfo(double latitude, double longitude, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
{
- string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?q={CityName}&appid={APIKey}";
- return GetWeatherInfo(WeatherURL, Unit);
+ string WeatherURL = $"http://api.weather.com/v3/wx/forecast/daily/15day?geocode={latitude},{longitude}&format=json&language=en-US&units={(Unit == UnitMeasurement.Metric ? 'm' : 'e')}&apiKey={APIKey}";
+ return GetWeatherInfo(WeatherURL, Unit == UnitMeasurement.Kelvin ? UnitMeasurement.Imperial : Unit);
}
///
- /// Gets current weather info from OpenWeatherMap
+ /// Gets current weather info from The Weather Channel
///
/// An URL to the weather API request
/// The preferred unit to use
@@ -74,10 +63,7 @@ internal static WeatherForecastInfo GetWeatherInfo(string WeatherURL, UnitMeasur
Debug.WriteLine("Weather URL: {0} | Unit: {1}", WeatherURL, Unit);
// Deal with measurements
- if (Unit == UnitMeasurement.Imperial)
- WeatherURL += "&units=imperial";
- else
- WeatherURL += "&units=metric";
+ Unit = Unit == UnitMeasurement.Kelvin ? UnitMeasurement.Imperial : Unit;
// Download and parse JSON data
WeatherData = WeatherDownloader.GetStringAsync(WeatherURL).Result;
@@ -86,33 +72,21 @@ internal static WeatherForecastInfo GetWeatherInfo(string WeatherURL, UnitMeasur
}
///
- /// Gets current weather info from OpenWeatherMap
+ /// Gets current weather info from The Weather Channel
///
- /// City ID
+ /// City latitude
+ /// City longitude
/// API key
/// The preferred unit to use
/// A class containing properties of weather information
- public static async Task GetWeatherInfoAsync(long CityID, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
+ public static async Task GetWeatherInfoAsync(double latitude, double longitude, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
{
- string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?id={CityID}&appid={APIKey}";
+ string WeatherURL = $"http://api.weather.com/v3/wx/forecast/daily/15day?geocode={latitude},{longitude}&format=json&language=en-US&units={(Unit == UnitMeasurement.Metric ? 'm' : 'e')}&apiKey={APIKey}";
return await GetWeatherInfoAsync(WeatherURL, Unit);
}
///
- /// Gets current weather info from OpenWeatherMap
- ///
- /// City name
- /// API Key
- /// The preferred unit to use
- /// A class containing properties of weather information
- public static async Task GetWeatherInfoAsync(string CityName, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
- {
- string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?q={CityName}&appid={APIKey}";
- return await GetWeatherInfoAsync(WeatherURL, Unit);
- }
-
- ///
- /// Gets current weather info from OpenWeatherMap
+ /// Gets current weather info from The Weather Channel
///
/// An URL to the weather API request
/// The preferred unit to use
@@ -124,10 +98,7 @@ internal static async Task GetWeatherInfoAsync(string Weath
Debug.WriteLine("Weather URL: {0} | Unit: {1}", WeatherURL, Unit);
// Deal with measurements
- if (Unit == UnitMeasurement.Imperial)
- WeatherURL += "&units=imperial";
- else
- WeatherURL += "&units=metric";
+ Unit = Unit == UnitMeasurement.Kelvin ? UnitMeasurement.Imperial : Unit;
// Download and parse JSON data
WeatherData = await WeatherDownloader.GetStringAsync(WeatherURL);
@@ -140,15 +111,12 @@ internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, Un
WeatherForecastInfo WeatherInfo = new()
{
// Put needed data to the class
+ // TODO: Handle weather condition translation
Weather = (WeatherCondition)WeatherToken.SelectToken("weather").First.SelectToken("id").ToObject(typeof(WeatherCondition)),
- Temperature = (double)WeatherToken.SelectToken("main").SelectToken("temp").ToObject(typeof(double)),
- FeelsLike = (double)WeatherToken.SelectToken("main").SelectToken("feels_like").ToObject(typeof(double)),
- Pressure = (double)WeatherToken.SelectToken("main").SelectToken("pressure").ToObject(typeof(double)),
- Humidity = (double)WeatherToken.SelectToken("main").SelectToken("humidity").ToObject(typeof(double)),
- WindSpeed = (double)WeatherToken.SelectToken("wind").SelectToken("speed").ToObject(typeof(double)),
- WindDirection = (double)WeatherToken.SelectToken("wind").SelectToken("deg").ToObject(typeof(double)),
- CityID = (long)WeatherToken.SelectToken("id").ToObject(typeof(long)),
- CityName = (string)WeatherToken.SelectToken("name").ToObject(typeof(string)),
+ Temperature = (double)WeatherToken["daypart"]["temperature"][1].ToObject(typeof(double)),
+ Humidity = (double)WeatherToken["daypart"]["humidity"][1].ToObject(typeof(double)),
+ WindSpeed = (double)WeatherToken["daypart"]["windSpeed"][1].ToObject(typeof(double)),
+ WindDirection = (double)WeatherToken["daypart"]["windDirection"][1].ToObject(typeof(double)),
TemperatureMeasurement = Unit
};
return WeatherInfo;
@@ -157,9 +125,9 @@ internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, Un
///
/// Lists all the available cities
///
- public static Dictionary ListAllCities()
+ public static Dictionary ListAllCities(string city, string APIKey)
{
- string WeatherCityListURL = $"http://bulk.openweathermap.org/sample/city.list.json.gz";
+ string WeatherCityListURL = $"http://api.weather.com/v3/location/search?language=en-US&query={city}&format=json&apiKey={APIKey}";
Stream WeatherCityListDataStream;
Debug.WriteLine("Weather City List URL: {0}", WeatherCityListURL);
@@ -171,9 +139,9 @@ public static Dictionary ListAllCities()
///
/// Lists all the available cities
///
- public static async Task> ListAllCitiesAsync()
+ public static async Task> ListAllCitiesAsync(string city, string APIKey)
{
- string WeatherCityListURL = $"http://bulk.openweathermap.org/sample/city.list.json.gz";
+ string WeatherCityListURL = $"http://api.weather.com/v3/location/search?language=en-US&query={city}&format=json&apiKey={APIKey}";
Stream WeatherCityListDataStream;
Debug.WriteLine("Weather City List URL: {0}", WeatherCityListURL);
@@ -182,37 +150,32 @@ public static async Task> ListAllCitiesAsync()
return FinalizeCityList(WeatherCityListDataStream);
}
- internal static Dictionary FinalizeCityList(Stream WeatherCityListDataStream)
+ internal static Dictionary FinalizeCityList(Stream WeatherCityListDataStream)
{
- GZipStream WeatherCityListData;
- var WeatherCityListUncompressed = new List();
- int WeatherCityListReadByte = 0;
- JToken WeatherCityListToken;
- var WeatherCityList = new Dictionary();
-
- // Parse the weather list JSON. Since the output is gzipped, we'll have to uncompress it using stream, since the city list
- // is large anyways. This saves you from downloading full 45+ MB of text.
- WeatherCityListData = new GZipStream(WeatherCityListDataStream, CompressionMode.Decompress, false);
- while (WeatherCityListReadByte != -1)
- {
- WeatherCityListReadByte = WeatherCityListData.ReadByte();
- if (WeatherCityListReadByte != -1)
- WeatherCityListUncompressed.Add((byte)WeatherCityListReadByte);
- }
-
- WeatherCityListToken = JToken.Parse(Encoding.Default.GetString([.. WeatherCityListUncompressed]));
-
- // Put needed data to the class
- foreach (JToken WeatherCityToken in WeatherCityListToken)
+ // Get the token
+ var reader = new StreamReader(WeatherCityListDataStream);
+ string json = reader.ReadToEnd();
+ var token = JToken.Parse(json);
+
+ // Get the addresses, the latitudes, and the longitudes
+ var loc = token["location"];
+ var addresses = (JArray)loc["address"];
+ var latitudes = (JArray)loc["latitude"];
+ var longitudes = (JArray)loc["longitude"];
+ Debug.Assert(addresses.Count == latitudes.Count && addresses.Count == longitudes.Count && latitudes.Count == longitudes.Count);
+
+ // Put needed data
+ Dictionary cities = [];
+ for (int i = 0; i < addresses.Count; i++)
{
- long cityId = (long)WeatherCityToken["id"];
- string cityName = (string)WeatherCityToken["name"];
- if (!WeatherCityList.ContainsKey(cityId))
- WeatherCityList.Add(cityId, cityName);
+ var address = (string)addresses[i];
+ var lat = (double)latitudes[i];
+ var lng = (double)longitudes[i];
+ cities.Add(address, (lat, lng));
}
// Return list
- return WeatherCityList;
+ return cities;
}
}
}
diff --git a/Nettify/Weather/WeatherForecastInfo.cs b/Nettify/Weather/WeatherForecastInfo.cs
index be71478..0d73a31 100644
--- a/Nettify/Weather/WeatherForecastInfo.cs
+++ b/Nettify/Weather/WeatherForecastInfo.cs
@@ -24,17 +24,9 @@ namespace Nettify.Weather
///
/// Forecast information
///
- [DebuggerDisplay("{CityName} [{CityID}]: {Weather} @ {Temperature} [{TemperatureMeasurement}]")]
+ [DebuggerDisplay("{Weather} @ {Temperature} [{TemperatureMeasurement}]")]
public partial class WeatherForecastInfo
{
- ///
- /// City ID
- ///
- public long CityID { get; set; }
- ///
- /// City Name
- ///
- public string CityName { get; set; }
///
/// Weather condition
///
@@ -48,14 +40,6 @@ public partial class WeatherForecastInfo
///
public double Temperature { get; set; }
///
- /// Feels like
- ///
- public double FeelsLike { get; set; }
- ///
- /// Pressure in hPa
- ///
- public double Pressure { get; set; }
- ///
/// Humidity in percent
///
public double Humidity { get; set; }
diff --git a/Nettify/Weather/WeatherForecastOwm.cs b/Nettify/Weather/WeatherForecastOwm.cs
new file mode 100644
index 0000000..d192366
--- /dev/null
+++ b/Nettify/Weather/WeatherForecastOwm.cs
@@ -0,0 +1,214 @@
+//
+// Nettify Copyright (C) 2023-2024 Aptivi
+//
+// This file is part of Nettify
+//
+// Nettify is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Nettify is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY, without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json.Linq;
+
+namespace Nettify.Weather
+{
+ ///
+ /// The forecast tools (OpenWeatherMap)
+ ///
+ public static class WeatherForecastOwm
+ {
+ internal static HttpClient WeatherDownloader = new();
+
+ ///
+ /// Gets current weather info from OpenWeatherMap
+ ///
+ /// City ID
+ /// API key
+ /// The preferred unit to use
+ /// A class containing properties of weather information
+ public static WeatherForecastInfo GetWeatherInfo(long CityID, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?id={CityID}&appid={APIKey}";
+ return GetWeatherInfo(WeatherURL, Unit);
+ }
+
+ ///
+ /// Gets current weather info from OpenWeatherMap
+ ///
+ /// City name
+ /// API Key
+ /// The preferred unit to use
+ /// A class containing properties of weather information
+ public static WeatherForecastInfo GetWeatherInfo(string CityName, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?q={CityName}&appid={APIKey}";
+ return GetWeatherInfo(WeatherURL, Unit);
+ }
+
+ ///
+ /// Gets current weather info from OpenWeatherMap
+ ///
+ /// An URL to the weather API request
+ /// The preferred unit to use
+ /// A class containing properties of weather information
+ internal static WeatherForecastInfo GetWeatherInfo(string WeatherURL, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ string WeatherData;
+ JToken WeatherToken;
+ Debug.WriteLine("Weather URL: {0} | Unit: {1}", WeatherURL, Unit);
+
+ // Deal with measurements
+ if (Unit == UnitMeasurement.Imperial)
+ WeatherURL += "&units=imperial";
+ else
+ WeatherURL += "&units=metric";
+
+ // Download and parse JSON data
+ WeatherData = WeatherDownloader.GetStringAsync(WeatherURL).Result;
+ WeatherToken = JToken.Parse(WeatherData);
+ return FinalizeInstallation(WeatherToken, Unit);
+ }
+
+ ///
+ /// Gets current weather info from OpenWeatherMap
+ ///
+ /// City ID
+ /// API key
+ /// The preferred unit to use
+ /// A class containing properties of weather information
+ public static async Task GetWeatherInfoAsync(long CityID, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?id={CityID}&appid={APIKey}";
+ return await GetWeatherInfoAsync(WeatherURL, Unit);
+ }
+
+ ///
+ /// Gets current weather info from OpenWeatherMap
+ ///
+ /// City name
+ /// API Key
+ /// The preferred unit to use
+ /// A class containing properties of weather information
+ public static async Task GetWeatherInfoAsync(string CityName, string APIKey, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ string WeatherURL = $"http://api.openweathermap.org/data/2.5/weather?q={CityName}&appid={APIKey}";
+ return await GetWeatherInfoAsync(WeatherURL, Unit);
+ }
+
+ ///
+ /// Gets current weather info from OpenWeatherMap
+ ///
+ /// An URL to the weather API request
+ /// The preferred unit to use
+ /// A class containing properties of weather information
+ internal static async Task GetWeatherInfoAsync(string WeatherURL, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ string WeatherData;
+ JToken WeatherToken;
+ Debug.WriteLine("Weather URL: {0} | Unit: {1}", WeatherURL, Unit);
+
+ // Deal with measurements
+ if (Unit == UnitMeasurement.Imperial)
+ WeatherURL += "&units=imperial";
+ else
+ WeatherURL += "&units=metric";
+
+ // Download and parse JSON data
+ WeatherData = await WeatherDownloader.GetStringAsync(WeatherURL);
+ WeatherToken = JToken.Parse(WeatherData);
+ return FinalizeInstallation(WeatherToken, Unit);
+ }
+
+ internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, UnitMeasurement Unit = UnitMeasurement.Metric)
+ {
+ WeatherForecastInfo WeatherInfo = new()
+ {
+ // Put needed data to the class
+ Weather = (WeatherCondition)WeatherToken.SelectToken("weather").First.SelectToken("id").ToObject(typeof(WeatherCondition)),
+ Temperature = (double)WeatherToken.SelectToken("main").SelectToken("temp").ToObject(typeof(double)),
+ Humidity = (double)WeatherToken.SelectToken("main").SelectToken("humidity").ToObject(typeof(double)),
+ WindSpeed = (double)WeatherToken.SelectToken("wind").SelectToken("speed").ToObject(typeof(double)),
+ WindDirection = (double)WeatherToken.SelectToken("wind").SelectToken("deg").ToObject(typeof(double)),
+ TemperatureMeasurement = Unit
+ };
+ return WeatherInfo;
+ }
+
+ ///
+ /// Lists all the available cities
+ ///
+ public static Dictionary ListAllCities()
+ {
+ string WeatherCityListURL = $"http://bulk.openweathermap.org/sample/city.list.json.gz";
+ Stream WeatherCityListDataStream;
+ Debug.WriteLine("Weather City List URL: {0}", WeatherCityListURL);
+
+ // Open the stream to the city list URL
+ WeatherCityListDataStream = WeatherDownloader.GetStreamAsync(WeatherCityListURL).Result;
+ return FinalizeCityList(WeatherCityListDataStream);
+ }
+
+ ///
+ /// Lists all the available cities
+ ///
+ public static async Task> ListAllCitiesAsync()
+ {
+ string WeatherCityListURL = $"http://bulk.openweathermap.org/sample/city.list.json.gz";
+ Stream WeatherCityListDataStream;
+ Debug.WriteLine("Weather City List URL: {0}", WeatherCityListURL);
+
+ // Open the stream to the city list URL
+ WeatherCityListDataStream = await WeatherDownloader.GetStreamAsync(WeatherCityListURL);
+ return FinalizeCityList(WeatherCityListDataStream);
+ }
+
+ internal static Dictionary FinalizeCityList(Stream WeatherCityListDataStream)
+ {
+ GZipStream WeatherCityListData;
+ var WeatherCityListUncompressed = new List();
+ int WeatherCityListReadByte = 0;
+ JToken WeatherCityListToken;
+ var WeatherCityList = new Dictionary();
+
+ // Parse the weather list JSON. Since the output is gzipped, we'll have to uncompress it using stream, since the city list
+ // is large anyways. This saves you from downloading full 45+ MB of text.
+ WeatherCityListData = new GZipStream(WeatherCityListDataStream, CompressionMode.Decompress, false);
+ while (WeatherCityListReadByte != -1)
+ {
+ WeatherCityListReadByte = WeatherCityListData.ReadByte();
+ if (WeatherCityListReadByte != -1)
+ WeatherCityListUncompressed.Add((byte)WeatherCityListReadByte);
+ }
+
+ WeatherCityListToken = JToken.Parse(Encoding.Default.GetString([.. WeatherCityListUncompressed]));
+
+ // Put needed data to the class
+ foreach (JToken WeatherCityToken in WeatherCityListToken)
+ {
+ long cityId = (long)WeatherCityToken["id"];
+ string cityName = (string)WeatherCityToken["name"];
+ if (!WeatherCityList.ContainsKey(cityId))
+ WeatherCityList.Add(cityId, cityName);
+ }
+
+ // Return list
+ return WeatherCityList;
+ }
+ }
+}