diff --git a/MediaBrowser.Api/HttpHandlers/GenreHandler.cs b/MediaBrowser.Api/HttpHandlers/GenreHandler.cs
index c2b70e1066..eeadf1e453 100644
--- a/MediaBrowser.Api/HttpHandlers/GenreHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/GenreHandler.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Api.HttpHandlers
///
/// Gets a single genre
///
- public class GenreHandler : BaseJsonHandler
+ public class GenreHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs
index b5608c0a3d..9be2efa173 100644
--- a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs
@@ -9,7 +9,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
- public class GenresHandler : BaseJsonHandler
+ public class GenresHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs
index 4f2a9c68e5..35310f042b 100644
--- a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs
@@ -8,7 +8,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
- public class ItemHandler : BaseJsonHandler
+ public class ItemHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
index 9d5e3eb580..09814b191d 100644
--- a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
@@ -9,7 +9,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
- public class ItemListHandler : BaseJsonHandler
+ public class ItemListHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs
index 3c34efae50..0d496c2406 100644
--- a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Api.HttpHandlers
///
/// Gets a single Person
///
- public class PersonHandler : BaseJsonHandler
+ public class PersonHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs
index fbc16109d8..6abfb9b2d8 100644
--- a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs
@@ -7,7 +7,7 @@ using MediaBrowser.Model.Plugins;
namespace MediaBrowser.Api.HttpHandlers
{
- public class PluginConfigurationHandler : BaseJsonHandler
+ public class PluginConfigurationHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs
index 1cb4e95f76..67246cbc6a 100644
--- a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs
@@ -10,7 +10,7 @@ namespace MediaBrowser.Api.HttpHandlers
///
/// Provides information about installed plugins
///
- public class PluginsHandler : BaseJsonHandler>
+ public class PluginsHandler : BaseSerializationHandler>
{
protected override Task> GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs
index af7e7fed0b..458dd9da13 100644
--- a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Api.HttpHandlers
///
/// Gets a single studio
///
- public class StudioHandler : BaseJsonHandler
+ public class StudioHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
index 486aa762b9..d9805c43c8 100644
--- a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
@@ -9,7 +9,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
- public class StudiosHandler : BaseJsonHandler
+ public class StudiosHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs
index 44d23a208e..e7617fe881 100644
--- a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs
@@ -7,7 +7,7 @@ using MediaBrowser.Model.DTO;
namespace MediaBrowser.Api.HttpHandlers
{
- class UsersHandler : BaseJsonHandler>
+ class UsersHandler : BaseSerializationHandler>
{
protected override Task> GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/WeatherHandler.cs b/MediaBrowser.Api/HttpHandlers/WeatherHandler.cs
new file mode 100644
index 0000000000..b46473f119
--- /dev/null
+++ b/MediaBrowser.Api/HttpHandlers/WeatherHandler.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Controller;
+using MediaBrowser.Model.Weather;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+ class WeatherHandler : BaseSerializationHandler
+ {
+ protected override Task GetObjectToSerialize()
+ {
+ // If a specific zip code was requested on the query string, use that. Otherwise use the value from configuration
+
+ string zipCode = QueryString["zipcode"];
+
+ if (string.IsNullOrWhiteSpace(zipCode))
+ {
+ zipCode = Kernel.Instance.Configuration.WeatherZipCode;
+ }
+
+ return Kernel.Instance.WeatherClient.GetWeatherInfoAsync(zipCode);
+ }
+
+ ///
+ /// Tell the client to cache the weather info for 15 minutes
+ ///
+ public override TimeSpan CacheDuration
+ {
+ get
+ {
+ return TimeSpan.FromMinutes(15);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Api/HttpHandlers/YearHandler.cs b/MediaBrowser.Api/HttpHandlers/YearHandler.cs
index 0eb674e272..1b0c7f6704 100644
--- a/MediaBrowser.Api/HttpHandlers/YearHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/YearHandler.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Api.HttpHandlers
///
/// Gets a single year
///
- public class YearHandler : BaseJsonHandler
+ public class YearHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs
index ff05120a04..9a7325f649 100644
--- a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs
@@ -9,7 +9,7 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
- public class YearsHandler : BaseJsonHandler
+ public class YearsHandler : BaseSerializationHandler
{
protected override Task GetObjectToSerialize()
{
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index d234beb15b..5d32210938 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -69,6 +69,7 @@
+
diff --git a/MediaBrowser.Api/Plugin.cs b/MediaBrowser.Api/Plugin.cs
index 97d4a58652..467b30ef15 100644
--- a/MediaBrowser.Api/Plugin.cs
+++ b/MediaBrowser.Api/Plugin.cs
@@ -101,6 +101,10 @@ namespace MediaBrowser.Api
{
return new StudioHandler();
}
+ else if (localPath.EndsWith("/api/weather", StringComparison.OrdinalIgnoreCase))
+ {
+ return new WeatherHandler();
+ }
return null;
}
diff --git a/MediaBrowser.ApiInteraction/ApiClient.cs b/MediaBrowser.ApiInteraction/ApiClient.cs
index 149529b809..99af250ca8 100644
--- a/MediaBrowser.ApiInteraction/ApiClient.cs
+++ b/MediaBrowser.ApiInteraction/ApiClient.cs
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Threading.Tasks;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Weather;
namespace MediaBrowser.ApiInteraction
{
@@ -564,6 +565,32 @@ namespace MediaBrowser.ApiInteraction
}
}
+ ///
+ /// Gets weather information for the default location as set in configuration
+ ///
+ public async Task GetWeatherInfo()
+ {
+ string url = ApiUrl + "/weather";
+
+ using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
+ {
+ return DeserializeFromStream(stream);
+ }
+ }
+
+ ///
+ /// Gets weather information for a specific zip code
+ ///
+ public async Task GetWeatherInfo(string zipCode)
+ {
+ string url = ApiUrl + "/weather?zipcode=" + zipCode;
+
+ using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
+ {
+ return DeserializeFromStream(stream);
+ }
+ }
+
///
/// This is a helper around getting a stream from the server that contains serialized data
///
diff --git a/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs
index 1a366c158f..a0696d4a61 100644
--- a/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Common.Serialization;
namespace MediaBrowser.Common.Net.Handlers
{
- public abstract class BaseJsonHandler : BaseHandler
+ public abstract class BaseSerializationHandler : BaseHandler
{
public SerializationFormat SerializationFormat
{
diff --git a/MediaBrowser.Controller/Configuration/ServerConfiguration.cs b/MediaBrowser.Controller/Configuration/ServerConfiguration.cs
index f6dde3aa1c..368c8ef371 100644
--- a/MediaBrowser.Controller/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Controller/Configuration/ServerConfiguration.cs
@@ -5,5 +5,6 @@ namespace MediaBrowser.Controller.Configuration
public class ServerConfiguration : BaseApplicationConfiguration
{
public bool EnableInternetProviders { get; set; }
+ public string WeatherZipCode { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs
index daf5fcd24d..1a161ccc98 100644
--- a/MediaBrowser.Controller/Kernel.cs
+++ b/MediaBrowser.Controller/Kernel.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Controller.Weather;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Progress;
@@ -24,6 +25,7 @@ namespace MediaBrowser.Controller
public static Kernel Instance { get; private set; }
public ItemController ItemController { get; private set; }
+ public WeatherClient WeatherClient { get; private set; }
public IEnumerable Users { get; private set; }
public Folder RootFolder { get; private set; }
@@ -72,6 +74,7 @@ namespace MediaBrowser.Controller
ItemController = new ItemController();
DirectoryWatchers = new DirectoryWatchers();
+ WeatherClient = new WeatherClient();
ItemController.PreBeginResolvePath += ItemController_PreBeginResolvePath;
ItemController.BeginResolvePath += ItemController_BeginResolvePath;
@@ -228,7 +231,6 @@ namespace MediaBrowser.Controller
user.Name = "Default User";
user.Id = Guid.Parse("5d1cf7fce25943b790d140095457a42b");
- //user.PrimaryImagePath = "D:\\Video\\TV\\Archer (2009)\\folder.jpg";
list.Add(user);
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index ab141c79f1..f72202fea8 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -37,6 +37,8 @@
+
+
False
..\packages\Rx-Core.2.0.20823\lib\Net45\System.Reactive.Core.dll
@@ -77,6 +79,7 @@
+
diff --git a/MediaBrowser.Controller/Weather/WeatherClient.cs b/MediaBrowser.Controller/Weather/WeatherClient.cs
new file mode 100644
index 0000000000..c49c504773
--- /dev/null
+++ b/MediaBrowser.Controller/Weather/WeatherClient.cs
@@ -0,0 +1,191 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Cache;
+using System.Net.Http;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Logging;
+using MediaBrowser.Common.Serialization;
+using MediaBrowser.Model.Weather;
+
+namespace MediaBrowser.Controller.Weather
+{
+ ///
+ /// 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
+ ///
+ public class WeatherClient
+ {
+ private HttpClient HttpClient { get; set; }
+
+ public WeatherClient()
+ {
+ WebRequestHandler handler = new WebRequestHandler();
+
+ handler.AutomaticDecompression = DecompressionMethods.Deflate;
+ handler.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate);
+
+ HttpClient = new HttpClient(handler);
+ }
+
+ public async Task GetWeatherInfoAsync(string zipCode)
+ {
+ int numDays = 5;
+ string apiKey = "24902f60f1231941120109";
+
+ string url = "http://free.worldweatheronline.com/feed/weather.ashx?q=" + zipCode + "&format=json&num_of_days=" + numDays + "&key=" + apiKey;
+
+ Logger.LogInfo("Accessing weather from " + url);
+
+ using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false))
+ {
+ WeatherData data = JsonSerializer.DeserializeFromStream(stream).data;
+
+ return GetWeatherInfo(data);
+ }
+ }
+
+ ///
+ /// Converst the json output to our WeatherInfo model class
+ ///
+ private WeatherInfo GetWeatherInfo(WeatherData data)
+ {
+ WeatherInfo info = new WeatherInfo();
+
+ if (data.current_condition.Any())
+ {
+ info.CurrentWeather = data.current_condition.First().ToWeatherStatus();
+ }
+
+ info.Forecasts = data.weather.Select(w => w.ToWeatherForecast()).ToArray();
+
+ return info;
+ }
+ }
+
+ class WeatherResult
+ {
+ public WeatherData data { get; set; }
+ }
+
+ public class WeatherData
+ {
+ public WeatherCondition[] current_condition { get; set; }
+ public DailyWeatherInfo[] weather { get; set; }
+ }
+
+ public class WeatherCondition
+ {
+ public string temp_C { get; set; }
+ public string temp_F { get; set; }
+ public string humidity { get; set; }
+ public string weatherCode { get; set; }
+
+ public WeatherStatus ToWeatherStatus()
+ {
+ return new WeatherStatus()
+ {
+ TemperatureCelsius = int.Parse(temp_C),
+ TemperatureFahrenheit = int.Parse(temp_F),
+ Humidity = int.Parse(humidity),
+ Condition = DailyWeatherInfo.GetCondition(weatherCode)
+ };
+ }
+ }
+
+ public class DailyWeatherInfo
+ {
+ public string date { get; set; }
+ public string precipMM { get; set; }
+ public string tempMaxC { get; set; }
+ public string tempMaxF { get; set; }
+ public string tempMinC { get; set; }
+ public string tempMinF { get; set; }
+ public string weatherCode { get; set; }
+ public string winddir16Point { get; set; }
+ public string winddirDegree { get; set; }
+ public string winddirection { get; set; }
+ public string windspeedKmph { get; set; }
+ public string windspeedMiles { get; set; }
+
+ 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)
+ };
+ }
+
+ 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;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 9d9ae9f5f0..dabc6864ca 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -56,6 +56,9 @@
+
+
+
diff --git a/MediaBrowser.Model/Weather/WeatherForecast.cs b/MediaBrowser.Model/Weather/WeatherForecast.cs
new file mode 100644
index 0000000000..f77d92366a
--- /dev/null
+++ b/MediaBrowser.Model/Weather/WeatherForecast.cs
@@ -0,0 +1,30 @@
+using System;
+using ProtoBuf;
+
+namespace MediaBrowser.Model.Weather
+{
+ ///
+ /// Represents a weather forecase for a specific date
+ ///
+ [ProtoContract]
+ public class WeatherForecast
+ {
+ [ProtoMember(1)]
+ public DateTime Date { get; set; }
+
+ [ProtoMember(2)]
+ public int HighTemperatureFahrenheit { get; set; }
+
+ [ProtoMember(3)]
+ public int LowTemperatureFahrenheit { get; set; }
+
+ [ProtoMember(4)]
+ public int HighTemperatureCelsius { get; set; }
+
+ [ProtoMember(5)]
+ public int LowTemperatureCelsius { get; set; }
+
+ [ProtoMember(6)]
+ public WeatherConditions Condition { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Weather/WeatherInfo.cs b/MediaBrowser.Model/Weather/WeatherInfo.cs
new file mode 100644
index 0000000000..7cad4d2484
--- /dev/null
+++ b/MediaBrowser.Model/Weather/WeatherInfo.cs
@@ -0,0 +1,14 @@
+using ProtoBuf;
+
+namespace MediaBrowser.Model.Weather
+{
+ [ProtoContract]
+ public class WeatherInfo
+ {
+ [ProtoMember(1)]
+ public WeatherStatus CurrentWeather { get; set; }
+
+ [ProtoMember(2)]
+ public WeatherForecast[] Forecasts { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Weather/WeatherStatus.cs b/MediaBrowser.Model/Weather/WeatherStatus.cs
new file mode 100644
index 0000000000..7019d319b7
--- /dev/null
+++ b/MediaBrowser.Model/Weather/WeatherStatus.cs
@@ -0,0 +1,38 @@
+using ProtoBuf;
+
+namespace MediaBrowser.Model.Weather
+{
+ ///
+ /// Represents the current weather status
+ ///
+ [ProtoContract]
+ public class WeatherStatus
+ {
+ [ProtoMember(1)]
+ public int TemperatureFahrenheit { get; set; }
+
+ [ProtoMember(2)]
+ public int TemperatureCelsius { get; set; }
+
+ [ProtoMember(3)]
+ public int Humidity { get; set; }
+
+ [ProtoMember(4)]
+ public WeatherConditions Condition { get; set; }
+ }
+
+ public enum WeatherConditions
+ {
+ Sunny,
+ PartlyCloudy,
+ Cloudy,
+ Overcast,
+ Mist,
+ Snow,
+ Rain,
+ Sleet,
+ Fog,
+ Blizzard,
+ Thunderstorm
+ }
+}