diff --git a/MediaBrowser.Api/HttpHandlers/JsonHandler.cs b/MediaBrowser.Api/HttpHandlers/JsonHandler.cs index 90502a0c5f..06ce4c2d4e 100644 --- a/MediaBrowser.Api/HttpHandlers/JsonHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/JsonHandler.cs @@ -1,7 +1,6 @@ using System.IO; using MediaBrowser.Common.Net.Handlers; -using MediaBrowser.Controller; -using MediaBrowser.Common.Json; +using MediaBrowser.Common.Serialization; namespace MediaBrowser.Api.HttpHandlers { diff --git a/MediaBrowser.ApiInteraction/ApiClient.cs b/MediaBrowser.ApiInteraction/ApiClient.cs new file mode 100644 index 0000000000..f9234441ce --- /dev/null +++ b/MediaBrowser.ApiInteraction/ApiClient.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Net.Http; +using System.Threading.Tasks; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; + +namespace MediaBrowser.ApiInteraction +{ + public class ApiClient : BaseClient + { + public IJsonSerializer JsonSerializer { get; set; } + + public ApiClient() + : base() + { + } + + /// + /// Gets an image url that can be used to download an image from the api + /// + /// The Id of the item + /// The type of image requested + /// The image index, if there are multiple. Currently only applies to backdrops. Supply null or 0 for first backdrop. + /// Use if a fixed width is required. Aspect ratio will be preserved. + /// Use if a fixed height is required. Aspect ratio will be preserved. + /// Use if a max width is required. Aspect ratio will be preserved. + /// Use if a max height is required. Aspect ratio will be preserved. + /// Quality level, from 0-100. Currently only applies to JPG. The default value should suffice. + public string GetImageUrl(Guid itemId, ImageType imageType, int? imageIndex, int? width, int? height, int? maxWidth, int? maxHeight, int? quality) + { + string url = ApiUrl + "/image"; + + url += "?id=" + itemId.ToString(); + url += "&type=" + imageType.ToString(); + + if (imageIndex.HasValue) + { + url += "&index=" + imageIndex; + } + if (width.HasValue) + { + url += "&width=" + width; + } + if (height.HasValue) + { + url += "&height=" + height; + } + if (maxWidth.HasValue) + { + url += "&maxWidth=" + maxWidth; + } + if (maxHeight.HasValue) + { + url += "&maxHeight=" + maxHeight; + } + if (quality.HasValue) + { + url += "&quality=" + quality; + } + + return url; + } + + /// + /// Gets an image stream based on a url + /// + public async Task GetImageStream(string url) + { + Stream stream = await HttpClient.GetStreamAsync(url); + + // For now this assumes the response stream is compressed. We can always improve this later. + return new GZipStream(stream, CompressionMode.Decompress, false); + } + + /// + /// Gets a BaseItem + /// + public async Task> GetItemAsync(Guid id, Guid userId) + { + string url = ApiUrl + "/item?userId=" + userId.ToString(); + + if (id != Guid.Empty) + { + url += "&id=" + id.ToString(); + } + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream>(gzipStream); + } + } + } + + /// + /// Gets all Users + /// + public async Task> GetAllUsersAsync() + { + string url = ApiUrl + "/users"; + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream>(gzipStream); + } + } + } + + /// + /// Gets all Genres + /// + public async Task>> GetAllGenresAsync(Guid userId) + { + string url = ApiUrl + "/genres?userId=" + userId.ToString(); + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream>>(gzipStream); + } + } + } + + /// + /// Gets a Genre + /// + public async Task> GetGenreAsync(string name, Guid userId) + { + string url = ApiUrl + "/genre?userId=" + userId.ToString() + "&name=" + name; + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream>(gzipStream); + } + } + } + + /// + /// Gets all studious + /// + public async Task>> GetAllStudiosAsync(Guid userId) + { + string url = ApiUrl + "/studios?userId=" + userId.ToString(); + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream>>(gzipStream); + } + } + } + + /// + /// Gets the current personalized configuration + /// + public async Task GetUserConfigurationAsync(Guid userId) + { + string url = ApiUrl + "/userconfiguration?userId=" + userId.ToString(); + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream(gzipStream); + } + } + } + + /// + /// Gets a Studio + /// + public async Task> GetStudioAsync(string name, Guid userId) + { + string url = ApiUrl + "/studio?userId=" + userId.ToString() + "&name=" + name; + + using (Stream stream = await HttpClient.GetStreamAsync(url)) + { + using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false)) + { + return JsonSerializer.DeserializeFromStream>(gzipStream); + } + } + } + } +} diff --git a/MediaBrowser.ApiInteraction/BaseClient.cs b/MediaBrowser.ApiInteraction/BaseClient.cs new file mode 100644 index 0000000000..ab76b9e486 --- /dev/null +++ b/MediaBrowser.ApiInteraction/BaseClient.cs @@ -0,0 +1,25 @@ +using System; +using System.Net.Http; + +namespace MediaBrowser.ApiInteraction +{ + /// + /// Provides a base class used by the api and image services + /// + public abstract class BaseClient : IDisposable + { + public string ApiUrl { get; set; } + + protected HttpClient HttpClient { get; private set; } + + public BaseClient() + { + HttpClient = new HttpClient(); + } + + public void Dispose() + { + HttpClient.Dispose(); + } + } +} diff --git a/MediaBrowser.ApiInteraction/IJsonSerializer.cs b/MediaBrowser.ApiInteraction/IJsonSerializer.cs new file mode 100644 index 0000000000..41f4049bbe --- /dev/null +++ b/MediaBrowser.ApiInteraction/IJsonSerializer.cs @@ -0,0 +1,13 @@ +using System; +using System.IO; + +namespace MediaBrowser.ApiInteraction +{ + /// + /// Since ServiceStack Json is not portable, we need to abstract required json functions into an interface + /// + public interface IJsonSerializer + { + T DeserializeFromStream(Stream stream); + } +} diff --git a/MediaBrowser.ApiInteraction/MediaBrowser.ApiInteraction.csproj b/MediaBrowser.ApiInteraction/MediaBrowser.ApiInteraction.csproj new file mode 100644 index 0000000000..682d974da6 --- /dev/null +++ b/MediaBrowser.ApiInteraction/MediaBrowser.ApiInteraction.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {B1C27231-7017-4C9B-A678-DE891954FA38} + Library + Properties + MediaBrowser.ApiInteraction + MediaBrowser.ApiInteraction + v4.5 + Profile7 + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + MediaBrowser.Model + + + + + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.ApiInteraction/Properties/AssemblyInfo.cs b/MediaBrowser.ApiInteraction/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..a788c5f71e --- /dev/null +++ b/MediaBrowser.ApiInteraction/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MediaBrowser.ApiInteraction")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MediaBrowser.ApiInteraction")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 0fdc1f8131..cc3cb76f08 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -10,8 +10,8 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Logging; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; +using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Progress; -using MediaBrowser.Common.Json; namespace MediaBrowser.Common.Kernel { @@ -93,8 +93,6 @@ namespace MediaBrowser.Common.Kernel public virtual void Init(IProgress progress) { - JsonSerializer.Configure(); - ReloadLogger(); ReloadConfiguration(); diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 8c8146cdcb..7f0605f09a 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -50,7 +50,7 @@ - + diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index 98b6120f7e..e6ebfa5518 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -1,8 +1,8 @@ using System; using System.IO; using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Plugins; -using MediaBrowser.Common.Json; namespace MediaBrowser.Common.Plugins { diff --git a/MediaBrowser.Common/Json/JsonSerializer.cs b/MediaBrowser.Common/Serialization/JsonSerializer.cs similarity index 66% rename from MediaBrowser.Common/Json/JsonSerializer.cs rename to MediaBrowser.Common/Serialization/JsonSerializer.cs index 8e132c1528..57b285ceea 100644 --- a/MediaBrowser.Common/Json/JsonSerializer.cs +++ b/MediaBrowser.Common/Serialization/JsonSerializer.cs @@ -1,17 +1,24 @@ using System; using System.IO; -namespace MediaBrowser.Common.Json +namespace MediaBrowser.Common.Serialization { + /// + /// Provides a wrapper around third party json serialization. + /// public class JsonSerializer { public static void SerializeToStream(T obj, Stream stream) { + Configure(); + ServiceStack.Text.JsonSerializer.SerializeToStream(obj, stream); } public static void SerializeToFile(T obj, string file) { + Configure(); + using (StreamWriter streamWriter = new StreamWriter(file)) { ServiceStack.Text.JsonSerializer.SerializeToWriter(obj, streamWriter); @@ -20,6 +27,8 @@ namespace MediaBrowser.Common.Json public static object DeserializeFromFile(Type type, string file) { + Configure(); + using (Stream stream = File.OpenRead(file)) { return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream); @@ -28,6 +37,8 @@ namespace MediaBrowser.Common.Json public static T DeserializeFromFile(string file) { + Configure(); + using (Stream stream = File.OpenRead(file)) { return ServiceStack.Text.JsonSerializer.DeserializeFromStream(stream); @@ -36,18 +47,28 @@ namespace MediaBrowser.Common.Json public static T DeserializeFromStream(Stream stream) { + Configure(); + return ServiceStack.Text.JsonSerializer.DeserializeFromStream(stream); } public static T DeserializeFromString(string data) { + Configure(); + return ServiceStack.Text.JsonSerializer.DeserializeFromString(data); } - public static void Configure() + private static bool IsConfigured = false; + private static void Configure() { - ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; - ServiceStack.Text.JsConfig.IncludeNullValues = false; + if (!IsConfigured) + { + ServiceStack.Text.JsConfig.ExcludeTypeInfo = true; + ServiceStack.Text.JsConfig.IncludeNullValues = false; + + IsConfigured = true; + } } } } diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 5cc51d6a12..ca7fd382ac 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -6,8 +6,8 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -using MediaBrowser.Common.Json; using MediaBrowser.Common.Kernel; +using MediaBrowser.Common.Serialization; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 6f94baf31d..078c998c04 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "Medi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction", "MediaBrowser.ApiInteraction\MediaBrowser.ApiInteraction.csproj", "{B1C27231-7017-4C9B-A678-DE891954FA38}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Release|Any CPU.Build.0 = Release|Any CPU + {B1C27231-7017-4C9B-A678-DE891954FA38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1C27231-7017-4C9B-A678-DE891954FA38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1C27231-7017-4C9B-A678-DE891954FA38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1C27231-7017-4C9B-A678-DE891954FA38}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE