diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-21 01:02:10 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-21 01:02:10 -0500 |
| commit | ae4ffa75be378497d8db210c6864cde40f7c75f9 (patch) | |
| tree | 14d7a0610ff5117f3ea92ddaee71c219bbbc4865 /MediaBrowser.Controller | |
| parent | acf5b0b6ed173a3a9540d0585bd491a119d524cf (diff) | |
isolated weather and moved drawing classes up to the controller project
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Drawing/ImageExtensions.cs | 199 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Drawing/ImageHeader.cs | 216 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Drawing/ImageManager.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Kernel.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaBrowser.Controller.csproj | 5 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Plugins/PluginSecurityManager.cs | 39 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Weather/BaseWeatherProvider.cs | 37 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Weather/IWeatherProvider.cs | 20 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Weather/WeatherProvider.cs | 311 |
9 files changed, 479 insertions, 356 deletions
diff --git a/MediaBrowser.Controller/Drawing/ImageExtensions.cs b/MediaBrowser.Controller/Drawing/ImageExtensions.cs new file mode 100644 index 000000000..cecbfe74a --- /dev/null +++ b/MediaBrowser.Controller/Drawing/ImageExtensions.cs @@ -0,0 +1,199 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Controller.Drawing +{ + /// <summary> + /// Class ImageExtensions + /// </summary> + public static class ImageExtensions + { + /// <summary> + /// Saves the image. + /// </summary> + /// <param name="outputFormat">The output format.</param> + /// <param name="image">The image.</param> + /// <param name="toStream">To stream.</param> + /// <param name="quality">The quality.</param> + public static void Save(this Image image, ImageFormat outputFormat, Stream toStream, int quality) + { + // Use special save methods for jpeg and png that will result in a much higher quality image + // All other formats use the generic Image.Save + if (ImageFormat.Jpeg.Equals(outputFormat)) + { + SaveAsJpeg(image, toStream, quality); + } + else if (ImageFormat.Png.Equals(outputFormat)) + { + image.Save(toStream, ImageFormat.Png); + } + else + { + image.Save(toStream, outputFormat); + } + } + + /// <summary> + /// Saves the JPEG. + /// </summary> + /// <param name="image">The image.</param> + /// <param name="target">The target.</param> + /// <param name="quality">The quality.</param> + public static void SaveAsJpeg(this Image image, Stream target, int quality) + { + using (var encoderParameters = new EncoderParameters(1)) + { + encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); + image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters); + } + } + + /// <summary> + /// Gets the image codec info. + /// </summary> + /// <param name="mimeType">Type of the MIME.</param> + /// <returns>ImageCodecInfo.</returns> + private static ImageCodecInfo GetImageCodecInfo(string mimeType) + { + var encoders = ImageCodecInfo.GetImageEncoders(); + + return encoders.FirstOrDefault(i => i.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase)) ?? encoders.FirstOrDefault(); + } + + /// <summary> + /// Crops an image by removing whitespace and transparency from the edges + /// </summary> + /// <param name="bmp">The BMP.</param> + /// <returns>Bitmap.</returns> + /// <exception cref="System.Exception"></exception> + public static Bitmap CropWhitespace(this Bitmap bmp) + { + var width = bmp.Width; + var height = bmp.Height; + + var topmost = 0; + for (int row = 0; row < height; ++row) + { + if (IsAllWhiteRow(bmp, row, width)) + topmost = row; + else break; + } + + int bottommost = 0; + for (int row = height - 1; row >= 0; --row) + { + if (IsAllWhiteRow(bmp, row, width)) + bottommost = row; + else break; + } + + int leftmost = 0, rightmost = 0; + for (int col = 0; col < width; ++col) + { + if (IsAllWhiteColumn(bmp, col, height)) + leftmost = col; + else + break; + } + + for (int col = width - 1; col >= 0; --col) + { + if (IsAllWhiteColumn(bmp, col, height)) + rightmost = col; + else + break; + } + + if (rightmost == 0) rightmost = width; // As reached left + if (bottommost == 0) bottommost = height; // As reached top. + + var croppedWidth = rightmost - leftmost; + var croppedHeight = bottommost - topmost; + + if (croppedWidth == 0) // No border on left or right + { + leftmost = 0; + croppedWidth = width; + } + + if (croppedHeight == 0) // No border on top or bottom + { + topmost = 0; + croppedHeight = height; + } + + // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here + var thumbnail = bmp.PixelFormat.HasFlag(PixelFormat.Indexed) ? new Bitmap(croppedWidth, croppedHeight) : new Bitmap(croppedWidth, croppedHeight, bmp.PixelFormat); + + // Preserve the original resolution + thumbnail.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution); + + using (var thumbnailGraph = Graphics.FromImage(thumbnail)) + { + thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality; + thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; + thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; + thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; + thumbnailGraph.CompositingMode = CompositingMode.SourceOver; + + thumbnailGraph.DrawImage(bmp, + new RectangleF(0, 0, croppedWidth, croppedHeight), + new RectangleF(leftmost, topmost, croppedWidth, croppedHeight), + GraphicsUnit.Pixel); + } + return thumbnail; + } + + /// <summary> + /// Determines whether or not a row of pixels is all whitespace + /// </summary> + /// <param name="bmp">The BMP.</param> + /// <param name="row">The row.</param> + /// <param name="width">The width.</param> + /// <returns><c>true</c> if [is all white row] [the specified BMP]; otherwise, <c>false</c>.</returns> + private static bool IsAllWhiteRow(Bitmap bmp, int row, int width) + { + for (var i = 0; i < width; ++i) + { + if (!IsWhiteSpace(bmp.GetPixel(i, row))) + { + return false; + } + } + return true; + } + + /// <summary> + /// Determines whether or not a column of pixels is all whitespace + /// </summary> + /// <param name="bmp">The BMP.</param> + /// <param name="col">The col.</param> + /// <param name="height">The height.</param> + /// <returns><c>true</c> if [is all white column] [the specified BMP]; otherwise, <c>false</c>.</returns> + private static bool IsAllWhiteColumn(Bitmap bmp, int col, int height) + { + for (var i = 0; i < height; ++i) + { + if (!IsWhiteSpace(bmp.GetPixel(col, i))) + { + return false; + } + } + return true; + } + + /// <summary> + /// Determines if a color is whitespace + /// </summary> + /// <param name="color">The color.</param> + /// <returns><c>true</c> if [is white space] [the specified color]; otherwise, <c>false</c>.</returns> + private static bool IsWhiteSpace(Color color) + { + return (color.R == 255 && color.G == 255 && color.B == 255) || color.A == 0; + } + } +} diff --git a/MediaBrowser.Controller/Drawing/ImageHeader.cs b/MediaBrowser.Controller/Drawing/ImageHeader.cs new file mode 100644 index 000000000..7cc63eee9 --- /dev/null +++ b/MediaBrowser.Controller/Drawing/ImageHeader.cs @@ -0,0 +1,216 @@ +using MediaBrowser.Common.Logging; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Controller.Drawing +{ + /// <summary> + /// Taken from http://stackoverflow.com/questions/111345/getting-image-dimensions-without-reading-the-entire-file/111349 + /// http://www.codeproject.com/Articles/35978/Reading-Image-Headers-to-Get-Width-and-Height + /// Minor improvements including supporting unsigned 16-bit integers when decoding Jfif and added logic + /// to load the image using new Bitmap if reading the headers fails + /// </summary> + public static class ImageHeader + { + /// <summary> + /// The error message + /// </summary> + const string errorMessage = "Could not recognize image format."; + + /// <summary> + /// The image format decoders + /// </summary> + private static readonly Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDecoders = new Dictionary<byte[], Func<BinaryReader, Size>> + { + { new byte[] { 0x42, 0x4D }, DecodeBitmap }, + { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif }, + { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif }, + { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng }, + { new byte[] { 0xff, 0xd8 }, DecodeJfif }, + }; + + /// <summary> + /// Gets the dimensions of an image. + /// </summary> + /// <param name="path">The path of the image to get the dimensions of.</param> + /// <returns>The dimensions of the specified image.</returns> + /// <exception cref="ArgumentException">The image was of an unrecognised format.</exception> + public static Size GetDimensions(string path) + { + try + { + using (var fs = File.OpenRead(path)) + { + using (var binaryReader = new BinaryReader(fs)) + { + return GetDimensions(binaryReader); + } + } + } + catch + { + Logger.LogInfo("Failed to read image header for {0}. Doing it the slow way.", path); + + using (var fs = File.OpenRead(path)) + { + // Co it the old fashioned way + using (var b = Image.FromStream(fs, true, false)) + { + return b.Size; + } + } + } + } + + /// <summary> + /// Gets the dimensions of an image. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>Size.</returns> + /// <exception cref="System.ArgumentException">binaryReader</exception> + /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception> + private static Size GetDimensions(BinaryReader binaryReader) + { + int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length; + var magicBytes = new byte[maxMagicBytesLength]; + for (int i = 0; i < maxMagicBytesLength; i += 1) + { + magicBytes[i] = binaryReader.ReadByte(); + foreach (var kvPair in imageFormatDecoders) + { + if (StartsWith(magicBytes, kvPair.Key)) + { + return kvPair.Value(binaryReader); + } + } + } + + throw new ArgumentException(errorMessage, "binaryReader"); + } + + /// <summary> + /// Startses the with. + /// </summary> + /// <param name="thisBytes">The this bytes.</param> + /// <param name="thatBytes">The that bytes.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + private static bool StartsWith(byte[] thisBytes, byte[] thatBytes) + { + for (int i = 0; i < thatBytes.Length; i += 1) + { + if (thisBytes[i] != thatBytes[i]) + { + return false; + } + } + + return true; + } + + /// <summary> + /// Reads the little endian int16. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>System.Int16.</returns> + private static short ReadLittleEndianInt16(BinaryReader binaryReader) + { + var bytes = new byte[sizeof(short)]; + + for (int i = 0; i < sizeof(short); i += 1) + { + bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte(); + } + return BitConverter.ToInt16(bytes, 0); + } + + /// <summary> + /// Reads the little endian int32. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>System.Int32.</returns> + private static int ReadLittleEndianInt32(BinaryReader binaryReader) + { + var bytes = new byte[sizeof(int)]; + for (int i = 0; i < sizeof(int); i += 1) + { + bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte(); + } + return BitConverter.ToInt32(bytes, 0); + } + + /// <summary> + /// Decodes the bitmap. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>Size.</returns> + private static Size DecodeBitmap(BinaryReader binaryReader) + { + binaryReader.ReadBytes(16); + int width = binaryReader.ReadInt32(); + int height = binaryReader.ReadInt32(); + return new Size(width, height); + } + + /// <summary> + /// Decodes the GIF. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>Size.</returns> + private static Size DecodeGif(BinaryReader binaryReader) + { + int width = binaryReader.ReadInt16(); + int height = binaryReader.ReadInt16(); + return new Size(width, height); + } + + /// <summary> + /// Decodes the PNG. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>Size.</returns> + private static Size DecodePng(BinaryReader binaryReader) + { + binaryReader.ReadBytes(8); + int width = ReadLittleEndianInt32(binaryReader); + int height = ReadLittleEndianInt32(binaryReader); + return new Size(width, height); + } + + /// <summary> + /// Decodes the jfif. + /// </summary> + /// <param name="binaryReader">The binary reader.</param> + /// <returns>Size.</returns> + /// <exception cref="System.ArgumentException"></exception> + private static Size DecodeJfif(BinaryReader binaryReader) + { + while (binaryReader.ReadByte() == 0xff) + { + byte marker = binaryReader.ReadByte(); + short chunkLength = ReadLittleEndianInt16(binaryReader); + if (marker == 0xc0) + { + binaryReader.ReadByte(); + int height = ReadLittleEndianInt16(binaryReader); + int width = ReadLittleEndianInt16(binaryReader); + return new Size(width, height); + } + + if (chunkLength < 0) + { + var uchunkLength = (ushort)chunkLength; + binaryReader.ReadBytes(uchunkLength - 2); + } + else + { + binaryReader.ReadBytes(chunkLength - 2); + } + } + + throw new ArgumentException(errorMessage); + } + } +} diff --git a/MediaBrowser.Controller/Drawing/ImageManager.cs b/MediaBrowser.Controller/Drawing/ImageManager.cs index b493a97af..6dd641cba 100644 --- a/MediaBrowser.Controller/Drawing/ImageManager.cs +++ b/MediaBrowser.Controller/Drawing/ImageManager.cs @@ -1,10 +1,8 @@ -using MediaBrowser.Common.Drawing; -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Kernel; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 22c241fd4..f8f48d8de 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -192,8 +192,8 @@ namespace MediaBrowser.Controller /// Gets the list of currently registered weather prvoiders /// </summary> /// <value>The weather providers.</value> - [ImportMany(typeof(BaseWeatherProvider))] - public IEnumerable<BaseWeatherProvider> WeatherProviders { get; private set; } + [ImportMany(typeof(IWeatherProvider))] + public IEnumerable<IWeatherProvider> WeatherProviders { get; private set; } /// <summary> /// Gets the list of currently registered metadata prvoiders diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index f911f190d..da2bc23e8 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -76,6 +76,8 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <Compile Include="Drawing\ImageExtensions.cs" /> + <Compile Include="Drawing\ImageHeader.cs" /> <Compile Include="Drawing\ImageManager.cs" /> <Compile Include="Entities\AggregateFolder.cs" /> <Compile Include="Entities\Audio\Audio.cs" /> @@ -197,8 +199,7 @@ <Compile Include="Sorting\BaseItemComparer.cs" /> <Compile Include="Sorting\SortOrder.cs" /> <Compile Include="Updates\InstallationManager.cs" /> - <Compile Include="Weather\BaseWeatherProvider.cs" /> - <Compile Include="Weather\WeatherProvider.cs" /> + <Compile Include="Weather\IWeatherProvider.cs" /> <Compile Include="Providers\BaseItemXmlParser.cs" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Controller/Plugins/PluginSecurityManager.cs b/MediaBrowser.Controller/Plugins/PluginSecurityManager.cs index 341e3582b..5dbd6cbc6 100644 --- a/MediaBrowser.Controller/Plugins/PluginSecurityManager.cs +++ b/MediaBrowser.Controller/Plugins/PluginSecurityManager.cs @@ -6,12 +6,28 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.Plugins { + /// <summary> + /// Class PluginSecurityManager + /// </summary> public class PluginSecurityManager : BaseManager<Kernel> { + /// <summary> + /// The _is MB supporter + /// </summary> private bool? _isMBSupporter; + /// <summary> + /// The _is MB supporter initialized + /// </summary> private bool _isMBSupporterInitialized; + /// <summary> + /// The _is MB supporter sync lock + /// </summary> private object _isMBSupporterSyncLock = new object(); - + + /// <summary> + /// Gets a value indicating whether this instance is MB supporter. + /// </summary> + /// <value><c>true</c> if this instance is MB supporter; otherwise, <c>false</c>.</value> public bool IsMBSupporter { get @@ -21,15 +37,29 @@ namespace MediaBrowser.Controller.Plugins } } + /// <summary> + /// Initializes a new instance of the <see cref="PluginSecurityManager" /> class. + /// </summary> + /// <param name="kernel">The kernel.</param> public PluginSecurityManager(Kernel kernel) : base(kernel) { } + /// <summary> + /// Gets the registration status. + /// </summary> + /// <param name="feature">The feature.</param> + /// <param name="mb2Equivalent">The MB2 equivalent.</param> + /// <returns>Task{MBRegistrationRecord}.</returns> public async Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null) { return await MBRegistration.GetRegistrationStatus(feature, mb2Equivalent).ConfigureAwait(false); } + /// <summary> + /// Gets or sets the supporter key. + /// </summary> + /// <value>The supporter key.</value> public string SupporterKey { get { return MBRegistration.SupporterKey; } @@ -46,6 +76,10 @@ namespace MediaBrowser.Controller.Plugins } } + /// <summary> + /// Gets or sets the legacy key. + /// </summary> + /// <value>The legacy key.</value> public string LegacyKey { get { return MBRegistration.LegacyKey; } @@ -56,6 +90,9 @@ namespace MediaBrowser.Controller.Plugins } } + /// <summary> + /// Resets the supporter info. + /// </summary> private void ResetSupporterInfo() { _isMBSupporter = null; diff --git a/MediaBrowser.Controller/Weather/BaseWeatherProvider.cs b/MediaBrowser.Controller/Weather/BaseWeatherProvider.cs deleted file mode 100644 index 4ae7a3991..000000000 --- a/MediaBrowser.Controller/Weather/BaseWeatherProvider.cs +++ /dev/null @@ -1,37 +0,0 @@ -using MediaBrowser.Model.Weather; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Weather -{ - /// <summary> - /// Class BaseWeatherProvider - /// </summary> - public abstract class BaseWeatherProvider : IDisposable - { - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - } - - /// <summary> - /// Gets the weather info async. - /// </summary> - /// <param name="location">The location.</param> - /// <returns>Task{WeatherInfo}.</returns> - public abstract Task<WeatherInfo> GetWeatherInfoAsync(string location, CancellationToken cancellationToken); - } -} diff --git a/MediaBrowser.Controller/Weather/IWeatherProvider.cs b/MediaBrowser.Controller/Weather/IWeatherProvider.cs new file mode 100644 index 000000000..9060e5b9c --- /dev/null +++ b/MediaBrowser.Controller/Weather/IWeatherProvider.cs @@ -0,0 +1,20 @@ +using MediaBrowser.Model.Weather; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Weather +{ + /// <summary> + /// Interface IWeatherProvider + /// </summary> + public interface IWeatherProvider + { + /// <summary> + /// Gets the weather info async. + /// </summary> + /// <param name="location">The location.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{WeatherInfo}.</returns> + Task<WeatherInfo> GetWeatherInfoAsync(string location, CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.Controller/Weather/WeatherProvider.cs b/MediaBrowser.Controller/Weather/WeatherProvider.cs deleted file mode 100644 index 1560aa92c..000000000 --- a/MediaBrowser.Controller/Weather/WeatherProvider.cs +++ /dev/null @@ -1,311 +0,0 @@ -using MediaBrowser.Common.Logging; -using MediaBrowser.Common.Serialization; -using MediaBrowser.Model.Weather; -using System; -using System.ComponentModel.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Weather -{ - /// <summary> - /// Based on http://www.worldweatheronline.com/free-weather-feed.aspx - /// The classes in this file are a reproduction of the json output, which will then be converted to our weather model classes - /// </summary> - [Export(typeof(BaseWeatherProvider))] - public class WeatherProvider : BaseWeatherProvider - { - /// <summary> - /// The _weather semaphore - /// </summary> - private readonly SemaphoreSlim _weatherSemaphore = new SemaphoreSlim(10, 10); - - /// <summary> - /// Gets the weather info async. - /// </summary> - /// <param name="location">The location.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{WeatherInfo}.</returns> - /// <exception cref="System.ArgumentNullException">location</exception> - public override async Task<WeatherInfo> GetWeatherInfoAsync(string location, CancellationToken cancellationToken) - { - if (string.IsNullOrWhiteSpace(location)) - { - throw new ArgumentNullException("location"); - } - - if (cancellationToken == null) - { - throw new ArgumentNullException("cancellationToken"); - } - - const int numDays = 5; - const string apiKey = "24902f60f1231941120109"; - - var url = "http://free.worldweatheronline.com/feed/weather.ashx?q=" + location + "&format=json&num_of_days=" + numDays + "&key=" + apiKey; - - Logger.LogInfo("Accessing weather from " + url); - - using (var stream = await Kernel.Instance.HttpManager.Get(url, _weatherSemaphore, cancellationToken).ConfigureAwait(false)) - { - var data = JsonSerializer.DeserializeFromStream<WeatherResult>(stream).data; - - return GetWeatherInfo(data); - } - } - - /// <summary> - /// Converst the json output to our WeatherInfo model class - /// </summary> - /// <param name="data">The data.</param> - /// <returns>WeatherInfo.</returns> - private WeatherInfo GetWeatherInfo(WeatherData data) - { - var info = new WeatherInfo(); - - if (data.current_condition != null) - { - var condition = data.current_condition.FirstOrDefault(); - - if (condition != null) - { - info.CurrentWeather = condition.ToWeatherStatus(); - } - } - - if (data.weather != null) - { - info.Forecasts = data.weather.Select(w => w.ToWeatherForecast()).ToArray(); - } - - return info; - } - } - - /// <summary> - /// Class WeatherResult - /// </summary> - class WeatherResult - { - /// <summary> - /// Gets or sets the data. - /// </summary> - /// <value>The data.</value> - public WeatherData data { get; set; } - } - - /// <summary> - /// Class WeatherData - /// </summary> - public class WeatherData - { - /// <summary> - /// Gets or sets the current_condition. - /// </summary> - /// <value>The current_condition.</value> - public WeatherCondition[] current_condition { get; set; } - /// <summary> - /// Gets or sets the weather. - /// </summary> - /// <value>The weather.</value> - public DailyWeatherInfo[] weather { get; set; } - } - - /// <summary> - /// Class WeatherCondition - /// </summary> - public class WeatherCondition - { - /// <summary> - /// Gets or sets the temp_ C. - /// </summary> - /// <value>The temp_ C.</value> - public string temp_C { get; set; } - /// <summary> - /// Gets or sets the temp_ F. - /// </summary> - /// <value>The temp_ F.</value> - public string temp_F { get; set; } - /// <summary> - /// Gets or sets the humidity. - /// </summary> - /// <value>The humidity.</value> - public string humidity { get; set; } - /// <summary> - /// Gets or sets the weather code. - /// </summary> - /// <value>The weather code.</value> - public string weatherCode { get; set; } - - /// <summary> - /// To the weather status. - /// </summary> - /// <returns>WeatherStatus.</returns> - public WeatherStatus ToWeatherStatus() - { - return new WeatherStatus - { - TemperatureCelsius = int.Parse(temp_C), - TemperatureFahrenheit = int.Parse(temp_F), - Humidity = int.Parse(humidity), - Condition = DailyWeatherInfo.GetCondition(weatherCode) - }; - } - } - - /// <summary> - /// Class DailyWeatherInfo - /// </summary> - public class DailyWeatherInfo - { - /// <summary> - /// Gets or sets the date. - /// </summary> - /// <value>The date.</value> - public string date { get; set; } - /// <summary> - /// Gets or sets the precip MM. - /// </summary> - /// <value>The precip MM.</value> - public string precipMM { get; set; } - /// <summary> - /// Gets or sets the temp max C. - /// </summary> - /// <value>The temp max C.</value> - public string tempMaxC { get; set; } - /// <summary> - /// Gets or sets the temp max F. - /// </summary> - /// <value>The temp max F.</value> - public string tempMaxF { get; set; } - /// <summary> - /// Gets or sets the temp min C. - /// </summary> - /// <value>The temp min C.</value> - public string tempMinC { get; set; } - /// <summary> - /// Gets or sets the temp min F. - /// </summary> - /// <value>The temp min F.</value> - public string tempMinF { get; set; } - /// <summary> - /// Gets or sets the weather code. - /// </summary> - /// <value>The weather code.</value> - public string weatherCode { get; set; } - /// <summary> - /// Gets or sets the winddir16 point. - /// </summary> - /// <value>The winddir16 point.</value> - public string winddir16Point { get; set; } - /// <summary> - /// Gets or sets the winddir degree. - /// </summary> - /// <value>The winddir degree.</value> - public string winddirDegree { get; set; } - /// <summary> - /// Gets or sets the winddirection. - /// </summary> - /// <value>The winddirection.</value> - public string winddirection { get; set; } - /// <summary> - /// Gets or sets the windspeed KMPH. - /// </summary> - /// <value>The windspeed KMPH.</value> - public string windspeedKmph { get; set; } - /// <summary> - /// Gets or sets the windspeed miles. - /// </summary> - /// <value>The windspeed miles.</value> - public string windspeedMiles { get; set; } - - /// <summary> - /// To the weather forecast. - /// </summary> - /// <returns>WeatherForecast.</returns> - public WeatherForecast ToWeatherForecast() - { - return new WeatherForecast - { - Date = DateTime.Parse(date), - HighTemperatureCelsius = int.Parse(tempMaxC), - HighTemperatureFahrenheit = int.Parse(tempMaxF), - LowTemperatureCelsius = int.Parse(tempMinC), - LowTemperatureFahrenheit = int.Parse(tempMinF), - Condition = GetCondition(weatherCode) - }; - } - - /// <summary> - /// Gets the condition. - /// </summary> - /// <param name="weatherCode">The weather code.</param> - /// <returns>WeatherConditions.</returns> - public static WeatherConditions GetCondition(string weatherCode) - { - switch (weatherCode) - { - case "362": - case "365": - case "320": - case "317": - case "182": - return WeatherConditions.Sleet; - case "338": - case "335": - case "332": - case "329": - case "326": - case "323": - case "377": - case "374": - case "371": - case "368": - case "395": - case "392": - case "350": - case "227": - case "179": - return WeatherConditions.Snow; - case "314": - case "311": - case "308": - case "305": - case "302": - case "299": - case "296": - case "293": - case "284": - case "281": - case "266": - case "263": - case "359": - case "356": - case "353": - case "185": - case "176": - return WeatherConditions.Rain; - case "260": - case "248": - return WeatherConditions.Fog; - case "389": - case "386": - case "200": - return WeatherConditions.Thunderstorm; - case "230": - return WeatherConditions.Blizzard; - case "143": - return WeatherConditions.Mist; - case "122": - return WeatherConditions.Overcast; - case "119": - return WeatherConditions.Cloudy; - case "115": - return WeatherConditions.PartlyCloudy; - default: - return WeatherConditions.Sunny; - } - } - } -} |
