LukePulverenti 12 năm trước cách đây
mục cha
commit
8ce3e74e81
93 tập tin đã thay đổi với 2450 bổ sung1576 xóa
  1. 0 0
      MediaBrowser.Api/Javascript/ApiClient.js
  2. 3 3
      MediaBrowser.Api/Javascript/JavascriptApiClientService.cs
  3. 23 2
      MediaBrowser.Api/LibraryService.cs
  4. 2 0
      MediaBrowser.Api/MediaBrowser.Api.csproj
  5. 25 4
      MediaBrowser.Api/PluginService.cs
  6. 29 4
      MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
  7. 32 3
      MediaBrowser.Api/SystemService.cs
  8. 51 14
      MediaBrowser.Api/UserLibrary/UserLibraryService.cs
  9. 39 6
      MediaBrowser.Api/UserService.cs
  10. 0 105
      MediaBrowser.ApiInteraction.Javascript/MediaBrowser.ApiInteraction.Javascript.csproj
  11. 0 30
      MediaBrowser.ApiInteraction.Javascript/Properties/AssemblyInfo.cs
  12. 0 8
      MediaBrowser.ApiInteraction.Javascript/packages.config
  13. 1 1
      MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
  14. 29 14
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  15. 4 4
      MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs
  16. 322 0
      MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
  17. 3 2
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  18. 3 2
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  19. 3 2
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
  20. 4 3
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs
  21. 23 42
      MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
  22. 7 6
      MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs
  23. 12 84
      MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
  24. 5 0
      MediaBrowser.Common.Implementations/packages.config
  25. 88 291
      MediaBrowser.Common/Kernel/BaseKernel.cs
  26. 21 0
      MediaBrowser.Common/Kernel/IApplicationHost.cs
  27. 76 0
      MediaBrowser.Common/Kernel/IApplicationPaths.cs
  28. 9 8
      MediaBrowser.Common/Kernel/IKernel.cs
  29. 17 4
      MediaBrowser.Common/Kernel/TcpManager.cs
  30. 2 17
      MediaBrowser.Common/MediaBrowser.Common.csproj
  31. 9 10
      MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs
  32. 1 1
      MediaBrowser.Common/Net/IWebSocket.cs
  33. 26 7
      MediaBrowser.Common/Net/WebSocketConnection.cs
  34. 17 5
      MediaBrowser.Common/Plugins/BasePlugin.cs
  35. 3 1
      MediaBrowser.Common/Plugins/IPlugin.cs
  36. 19 121
      MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs
  37. 0 64
      MediaBrowser.Common/ScheduledTasks/BaseTaskTrigger.cs
  38. 16 14
      MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
  39. 7 1
      MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs
  40. 27 2
      MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
  41. 26 0
      MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
  42. 16 14
      MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
  43. 2 2
      MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs
  44. 21 4
      MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
  45. 20 3
      MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
  46. 0 159
      MediaBrowser.Common/ScheduledTasks/TaskManager.cs
  47. 16 14
      MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
  48. 0 1
      MediaBrowser.Common/packages.config
  49. 30 15
      MediaBrowser.Controller/Drawing/ImageManager.cs
  50. 7 8
      MediaBrowser.Controller/Entities/User.cs
  51. 85 0
      MediaBrowser.Controller/IServerApplicationPaths.cs
  52. 31 33
      MediaBrowser.Controller/Kernel.cs
  53. 1 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  54. 58 21
      MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
  55. 23 7
      MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs
  56. 26 5
      MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
  57. 6 2
      MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs
  58. 6 2
      MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs
  59. 25 4
      MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
  60. 2 2
      MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs
  61. 4 3
      MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs
  62. 2 2
      MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs
  63. 2 2
      MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs
  64. 2 2
      MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs
  65. 29 17
      MediaBrowser.Controller/Updates/InstallationManager.cs
  66. 3 0
      MediaBrowser.Model/MediaBrowser.Model.csproj
  67. 103 0
      MediaBrowser.Model/Serialization/IJsonSerializer.cs
  68. 63 0
      MediaBrowser.Model/Serialization/IProtobufSerializer.cs
  69. 69 0
      MediaBrowser.Model/Serialization/IXmlSerializer.cs
  70. 2 0
      MediaBrowser.Networking/MediaBrowser.Networking.csproj
  71. 19 2
      MediaBrowser.Networking/Web/HttpServer.cs
  72. 3 17
      MediaBrowser.Networking/Web/NativeWebSocket.cs
  73. 28 0
      MediaBrowser.Networking/Web/ServerFactory.cs
  74. 4 4
      MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs
  75. 30 26
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  76. 4 5
      MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs
  77. 4 3
      MediaBrowser.Server.Implementations/ServerApplicationPaths.cs
  78. 31 6
      MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
  79. 1 1
      MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs
  80. 33 8
      MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
  81. 1 1
      MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
  82. 31 6
      MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
  83. 33 8
      MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
  84. 17 4
      MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs
  85. 0 0
      MediaBrowser.Server.Implementations/packages.config
  86. 11 183
      MediaBrowser.ServerApplication/App.xaml.cs
  87. 498 0
      MediaBrowser.ServerApplication/ApplicationHost.cs
  88. 9 6
      MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
  89. 13 2
      MediaBrowser.ServerApplication/MainWindow.xaml.cs
  90. 9 30
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  91. 0 5
      MediaBrowser.ServerApplication/packages.config
  92. 1 2
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  93. 32 49
      MediaBrowser.sln

+ 0 - 0
MediaBrowser.ApiInteraction.Javascript/ApiClient.js → MediaBrowser.Api/Javascript/ApiClient.js


+ 3 - 3
MediaBrowser.ApiInteraction.Javascript/JavascriptApiClientService.cs → MediaBrowser.Api/Javascript/JavascriptApiClientService.cs

@@ -5,13 +5,13 @@ using System;
 using System.IO;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.ApiInteraction.Javascript
+namespace MediaBrowser.Api.Javascript
 {
     /// <summary>
     /// Class GetJavascriptApiClient
     /// </summary>
     [Route("/JsApiClient.js", "GET")]
-    [Api(("Gets an api wrapper in Javascript"))]
+    [ServiceStack.ServiceHost.Api(("Gets an api wrapper in Javascript"))]
     public class GetJavascriptApiClient
     {
         /// <summary>
@@ -52,7 +52,7 @@ namespace MediaBrowser.ApiInteraction.Javascript
         /// <returns>Stream.</returns>
         private Task<Stream> GetStream()
         {
-            return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.ApiInteraction.Javascript.ApiClient.js"));
+            return Task.FromResult(GetType().Assembly.GetManifestResourceStream("MediaBrowser.Api.Javascript.ApiClient.js"));
         }
     }
 }

+ 23 - 2
MediaBrowser.Api/LibraryService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -97,6 +98,26 @@ namespace MediaBrowser.Api
     /// </summary>
     public class LibraryService : BaseRestService
     {
+        /// <summary>
+        /// The _app host
+        /// </summary>
+        private readonly IApplicationHost _appHost;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LibraryService" /> class.
+        /// </summary>
+        /// <param name="appHost">The app host.</param>
+        /// <exception cref="System.ArgumentNullException">appHost</exception>
+        public LibraryService(IApplicationHost appHost)
+        {
+            if (appHost == null)
+            {
+                throw new ArgumentNullException("appHost");
+            }
+
+            _appHost = appHost;
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -210,7 +231,7 @@ namespace MediaBrowser.Api
         {
             var kernel = (Kernel)Kernel;
 
-            var allTypes = kernel.AllTypes.Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(BaseItem)));
+            var allTypes = _appHost.AllConcreteTypes.Where(t => t.IsSubclassOf(typeof(BaseItem)));
 
             if (request.HasInternetProvider)
             {

+ 2 - 0
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -80,6 +80,7 @@
     <Compile Include="Images\ImageService.cs" />
     <Compile Include="Images\ImageWriter.cs" />
     <Compile Include="Images\UploadImageHandler.cs" />
+    <Compile Include="Javascript\JavascriptApiClientService.cs" />
     <Compile Include="LibraryService.cs" />
     <Compile Include="LocalizationService.cs" />
     <Compile Include="PackageService.cs" />
@@ -128,6 +129,7 @@
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
+    <EmbeddedResource Include="Javascript\ApiClient.js" />
     <Content Include="options.xml" />
   </ItemGroup>
   <ItemGroup />

+ 25 - 4
MediaBrowser.Api/PluginService.cs

@@ -1,15 +1,15 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
 using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using ServiceStack.Text.Controller;
 
 namespace MediaBrowser.Api
 {
@@ -119,6 +119,27 @@ namespace MediaBrowser.Api
     /// </summary>
     public class PluginService : BaseRestService
     {
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PluginService" /> class.
+        /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
+        public PluginService(IJsonSerializer jsonSerializer)
+            : base()
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _jsonSerializer = jsonSerializer;
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -198,7 +219,7 @@ namespace MediaBrowser.Api
         {
             var kernel = (Kernel)Kernel;
 
-            var info = JsonSerializer.DeserializeFromStream<PluginSecurityInfo>(request.RequestStream);
+            var info = _jsonSerializer.DeserializeFromStream<PluginSecurityInfo>(request.RequestStream);
 
             kernel.PluginSecurityManager.SupporterKey = info.SupporterKey;
             kernel.PluginSecurityManager.LegacyKey = info.LegacyKey;
@@ -217,7 +238,7 @@ namespace MediaBrowser.Api
 
             var plugin = Kernel.Plugins.First(p => p.Id == id);
 
-            var configuration = JsonSerializer.DeserializeFromStream(request.RequestStream, plugin.ConfigurationType) as BasePluginConfiguration;
+            var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, plugin.ConfigurationType) as BasePluginConfiguration;
 
             plugin.UpdateConfiguration(configuration);
         }

+ 29 - 4
MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs

@@ -1,7 +1,7 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Common.Serialization;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Tasks;
 using ServiceStack.ServiceHost;
 using System;
@@ -90,11 +90,32 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// <value>The task manager.</value>
         private ITaskManager TaskManager { get; set; }
 
-        public ScheduledTaskService(ITaskManager taskManager)
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScheduledTaskService" /> class.
+        /// </summary>
+        /// <param name="taskManager">The task manager.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">taskManager</exception>
+        public ScheduledTaskService(ITaskManager taskManager, IJsonSerializer jsonSerializer)
         {
+            if (taskManager == null)
+            {
+                throw new ArgumentNullException("taskManager");
+            }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
             TaskManager = taskManager;
+            _jsonSerializer = jsonSerializer;
         }
-        
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -113,6 +134,7 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// </summary>
         /// <param name="request">The request.</param>
         /// <returns>IEnumerable{TaskInfo}.</returns>
+        /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception>
         public object Get(GetScheduledTask request)
         {
             var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id);
@@ -131,6 +153,7 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// Posts the specified request.
         /// </summary>
         /// <param name="request">The request.</param>
+        /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception>
         public void Post(StartScheduledTask request)
         {
             var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id);
@@ -147,6 +170,7 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// Posts the specified request.
         /// </summary>
         /// <param name="request">The request.</param>
+        /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception>
         public void Delete(StopScheduledTask request)
         {
             var task = TaskManager.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id);
@@ -163,6 +187,7 @@ namespace MediaBrowser.Api.ScheduledTasks
         /// Posts the specified request.
         /// </summary>
         /// <param name="request">The request.</param>
+        /// <exception cref="MediaBrowser.Common.Extensions.ResourceNotFoundException">Task not found</exception>
         public void Post(UpdateScheduledTaskTriggers request)
         {
             // We need to parse this manually because we told service stack not to with IRequiresRequestStream
@@ -177,7 +202,7 @@ namespace MediaBrowser.Api.ScheduledTasks
                 throw new ResourceNotFoundException("Task not found");
             }
 
-            var triggerInfos = JsonSerializer.DeserializeFromStream<TaskTriggerInfo[]>(request.RequestStream);
+            var triggerInfos = _jsonSerializer.DeserializeFromStream<TaskTriggerInfo[]>(request.RequestStream);
 
             task.Triggers = triggerInfos.Select(ScheduledTaskHelpers.GetTrigger);
         }

+ 32 - 3
MediaBrowser.Api/SystemService.cs

@@ -1,15 +1,19 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
 using ServiceStack.ServiceHost;
+using System;
 using System.IO;
 using System.Threading.Tasks;
 
 namespace MediaBrowser.Api
 {
+    /// <summary>
+    /// Class GetSystemInfo
+    /// </summary>
     [Route("/System/Info", "GET")]
     public class GetSystemInfo : IReturn<SystemInfo>
     {
@@ -40,6 +44,10 @@ namespace MediaBrowser.Api
     [Route("/System/Configuration", "POST")]
     public class UpdateConfiguration : IRequiresRequestStream
     {
+        /// <summary>
+        /// The raw Http Request Input Stream
+        /// </summary>
+        /// <value>The request stream.</value>
         public Stream RequestStream { get; set; }
     }
 
@@ -48,6 +56,27 @@ namespace MediaBrowser.Api
     /// </summary>
     public class SystemService : BaseRestService
     {
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SystemService" /> class.
+        /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
+        public SystemService(IJsonSerializer jsonSerializer)
+            : base()
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _jsonSerializer = jsonSerializer;
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -95,8 +124,8 @@ namespace MediaBrowser.Api
         /// <param name="request">The request.</param>
         public void Post(UpdateConfiguration request)
         {
-            var serverConfig = JsonSerializer.DeserializeFromStream<ServerConfiguration>(request.RequestStream);
-            
+            var serverConfig = _jsonSerializer.DeserializeFromStream<ServerConfiguration>(request.RequestStream);
+
             var kernel = (Kernel)Kernel;
 
             kernel.UpdateConfiguration(serverConfig);

+ 51 - 14
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -1,11 +1,11 @@
 using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Serialization;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;
@@ -28,7 +28,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -48,7 +48,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the item id.
         /// </summary>
@@ -68,7 +68,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -106,7 +106,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -125,7 +125,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -144,7 +144,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -163,7 +163,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// <value>The user id.</value>
         public Guid UserId { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -215,6 +215,9 @@ namespace MediaBrowser.Api.UserLibrary
         public string Id { get; set; }
     }
 
+    /// <summary>
+    /// Class GetLocalTrailers
+    /// </summary>
     [Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET")]
     public class GetLocalTrailers : IReturn<List<BaseItemDto>>
     {
@@ -231,6 +234,9 @@ namespace MediaBrowser.Api.UserLibrary
         public string Id { get; set; }
     }
 
+    /// <summary>
+    /// Class GetSpecialFeatures
+    /// </summary>
     [Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")]
     public class GetSpecialFeatures : IReturn<List<BaseItemDto>>
     {
@@ -253,6 +259,32 @@ namespace MediaBrowser.Api.UserLibrary
     /// </summary>
     public class UserLibraryService : BaseRestService
     {
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="UserLibraryService" /> class.
+        /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
+        public UserLibraryService(IJsonSerializer jsonSerializer)
+            : base()
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _jsonSerializer = jsonSerializer;
+        }
+
+        /// <summary>
+        /// Gets the specified request.
+        /// </summary>
+        /// <param name="request">The request.</param>
+        /// <returns>System.Object.</returns>
         public object Get(GetSpecialFeatures request)
         {
             var kernel = (Kernel)Kernel;
@@ -260,7 +292,7 @@ namespace MediaBrowser.Api.UserLibrary
             var user = kernel.GetUserById(request.UserId);
 
             var item = DtoBuilder.GetItemByClientId(request.Id, user.Id);
-            
+
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
@@ -272,7 +304,12 @@ namespace MediaBrowser.Api.UserLibrary
 
             return ToOptimizedResult(items);
         }
-        
+
+        /// <summary>
+        /// Gets the specified request.
+        /// </summary>
+        /// <param name="request">The request.</param>
+        /// <returns>System.Object.</returns>
         public object Get(GetLocalTrailers request)
         {
             var kernel = (Kernel)Kernel;
@@ -280,7 +317,7 @@ namespace MediaBrowser.Api.UserLibrary
             var user = kernel.GetUserById(request.UserId);
 
             var item = DtoBuilder.GetItemByClientId(request.Id, user.Id);
-            
+
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
@@ -290,7 +327,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             return ToOptimizedResult(items);
         }
-        
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -303,7 +340,7 @@ namespace MediaBrowser.Api.UserLibrary
             var user = kernel.GetUserById(request.UserId);
 
             var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, user.Id);
-            
+
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
@@ -366,7 +403,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var item = (Folder)DtoBuilder.GetItemByClientId(itemId, user.Id);
 
-            var displayPreferences = JsonSerializer.DeserializeFromStream<DisplayPreferences>(request.RequestStream);
+            var displayPreferences = _jsonSerializer.DeserializeFromStream<DisplayPreferences>(request.RequestStream);
 
             var task = kernel.LibraryManager.SaveDisplayPreferencesForFolder(user, item, displayPreferences);
 

+ 39 - 6
MediaBrowser.Api/UserService.cs

@@ -1,16 +1,16 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Serialization;
 using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
-using ServiceStack.Text.Controller;
 
 namespace MediaBrowser.Api
 {
@@ -135,6 +135,39 @@ namespace MediaBrowser.Api
     /// </summary>
     public class UserService : BaseRestService
     {
+        /// <summary>
+        /// The _XML serializer
+        /// </summary>
+        private readonly IXmlSerializer _xmlSerializer;
+
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="UserService" /> class.
+        /// </summary>
+        /// <param name="xmlSerializer">The XML serializer.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">xmlSerializer</exception>
+        public UserService(IXmlSerializer xmlSerializer, IJsonSerializer jsonSerializer)
+            : base()
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            if (xmlSerializer == null)
+            {
+                throw new ArgumentNullException("xmlSerializer");
+            }
+
+            _jsonSerializer = jsonSerializer;
+            _xmlSerializer = xmlSerializer;
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -262,10 +295,10 @@ namespace MediaBrowser.Api
             // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
             var pathInfo = PathInfo.Parse(Request.PathInfo);
             var id = new Guid(pathInfo.GetArgumentValue<string>(1));
-            
+
             var kernel = (Kernel)Kernel;
 
-            var dtoUser = JsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream);
+            var dtoUser = _jsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream);
 
             var user = kernel.GetUserById(id);
 
@@ -273,7 +306,7 @@ namespace MediaBrowser.Api
 
             Task.WaitAll(task);
 
-            user.UpdateConfiguration(dtoUser.Configuration);
+            user.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer);
         }
 
         /// <summary>
@@ -285,7 +318,7 @@ namespace MediaBrowser.Api
         {
             var kernel = (Kernel)Kernel;
 
-            var dtoUser = JsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream);
+            var dtoUser = _jsonSerializer.DeserializeFromStream<UserDto>(request.RequestStream);
 
             var newUser = kernel.UserManager.CreateUser(dtoUser.Name).Result;
 

+ 0 - 105
MediaBrowser.ApiInteraction.Javascript/MediaBrowser.ApiInteraction.Javascript.csproj

@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{767B536E-D90C-4D74-A14B-8564B16F3499}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>MediaBrowser.ApiInteraction.Javascript</RootNamespace>
-    <AssemblyName>MediaBrowser.ApiInteraction.Javascript</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
-    <RestorePackages>true</RestorePackages>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup>
-    <RunPostBuildEvent>Always</RunPostBuildEvent>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.OrmLite.SqlServer, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Redis, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="Microsoft.CSharp" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\SharedVersion.cs">
-      <Link>Properties\SharedVersion.cs</Link>
-    </Compile>
-    <Compile Include="JavascriptApiClientService.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
-      <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
-      <Name>MediaBrowser.Common</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="ApiClient.js" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <PropertyGroup>
-    <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\MediaBrowser.ServerApplication\CorePlugins\" /y</PostBuildEvent>
-  </PropertyGroup>
-  <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>

+ 0 - 30
MediaBrowser.ApiInteraction.Javascript/Properties/AssemblyInfo.cs

@@ -1,30 +0,0 @@
-using System.Reflection;
-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.Javascript")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MediaBrowser.ApiInteraction.Javascript")]
-[assembly: AssemblyCopyright("Copyright ©  2012")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("97f9d4da-d7de-47d9-ae68-06d78679d327")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//

+ 0 - 8
MediaBrowser.ApiInteraction.Javascript/packages.config

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="ServiceStack" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
-</packages>

+ 1 - 1
MediaBrowser.Common/Kernel/BaseApplicationPaths.cs → MediaBrowser.Common.Implementations/BaseApplicationPaths.cs

@@ -3,7 +3,7 @@ using System.Configuration;
 using System.IO;
 using System.Reflection;
 
-namespace MediaBrowser.Common.Kernel
+namespace MediaBrowser.Common.Implementations
 {
     /// <summary>
     /// Provides a base class to hold common application paths used by both the Ui and Server.

+ 29 - 14
MediaBrowser.Server.WorldWeatherOnline/MediaBrowser.Server.WorldWeatherOnline.csproj → MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -4,13 +4,15 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{973CA45C-8362-490B-8327-C68098FD4891}</ProjectGuid>
+    <ProjectGuid>{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>MediaBrowser.Server.WorldWeatherOnline</RootNamespace>
-    <AssemblyName>MediaBrowser.Server.WorldWeatherOnline</AssemblyName>
+    <RootNamespace>MediaBrowser.Common.Implementations</RootNamespace>
+    <AssemblyName>MediaBrowser.Common.Implementations</AssemblyName>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+    <RestorePackages>true</RestorePackages>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -29,39 +31,52 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
-  <PropertyGroup>
-    <RunPostBuildEvent>Always</RunPostBuildEvent>
-  </PropertyGroup>
   <ItemGroup>
+    <Reference Include="protobuf-net">
+      <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath>
+    </Reference>
+    <Reference Include="ServiceStack.Text">
+      <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
+    <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\SharedVersion.cs">
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
+    <Compile Include="BaseApplicationPaths.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="WeatherProvider.cs" />
+    <Compile Include="ScheduledTasks\TaskManager.cs" />
+    <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
+    <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
+    <Compile Include="ScheduledTasks\Tasks\ReloadLoggerTask.cs" />
+    <Compile Include="ScheduledTasks\Tasks\SystemUpdateTask.cs" />
+    <Compile Include="Serialization\JsonSerializer.cs" />
+    <Compile Include="Serialization\ProtobufSerializer.cs" />
+    <Compile Include="Serialization\XmlSerializer.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>
     </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
-      <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
-      <Name>MediaBrowser.Controller</Name>
-    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
       <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <PropertyGroup>
-    <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\MediaBrowser.ServerApplication\CorePlugins\" /y</PostBuildEvent>
-  </PropertyGroup>
+  <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 4 - 4
MediaBrowser.Server.Sqlite/Properties/AssemblyInfo.cs → MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs

@@ -5,11 +5,11 @@ 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.Server.Sqlite")]
+[assembly: AssemblyTitle("MediaBrowser.Common.Implementations")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MediaBrowser.Server.Sqlite")]
+[assembly: AssemblyProduct("MediaBrowser.Common.Implementations")]
 [assembly: AssemblyCopyright("Copyright ©  2013")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
 [assembly: ComVisible(false)]
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("f46c9f4b-24ed-49e1-be19-4b6242dd8382")]
+[assembly: Guid("fc7d85c6-0fe7-4db6-8158-54f7b18f17cd")]
 
 // Version information for an assembly consists of the following four values:
 //
@@ -28,4 +28,4 @@ using System.Runtime.InteropServices;
 //      Minor Version 
 //      Build Number
 //      Revision
-//
+//

+ 322 - 0
MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs

@@ -0,0 +1,322 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Tasks;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Common.Implementations.ScheduledTasks
+{
+    /// <summary>
+    /// Class TaskManager
+    /// </summary>
+    public class TaskManager : ITaskManager
+    {
+        /// <summary>
+        /// Gets the list of Scheduled Tasks
+        /// </summary>
+        /// <value>The scheduled tasks.</value>
+        public IScheduledTask[] ScheduledTasks { get; private set; }
+
+        /// <summary>
+        /// The _task queue
+        /// </summary>
+        private readonly List<Type> _taskQueue = new List<Type>();
+
+        /// <summary>
+        /// The _logger
+        /// </summary>
+        private readonly ILogger _logger;
+
+        /// <summary>
+        /// The _application paths
+        /// </summary>
+        private readonly IApplicationPaths _applicationPaths;
+
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TaskManager" /> class.
+        /// </summary>
+        /// <param name="applicationPaths">The application paths.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="logger">The logger.</param>
+        /// <exception cref="System.ArgumentException">kernel</exception>
+        public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger)
+        {
+            if (applicationPaths == null)
+            {
+                throw new ArgumentException("applicationPaths");
+            }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentException("jsonSerializer");
+            }
+            if (logger == null)
+            {
+                throw new ArgumentException("logger");
+            }
+
+            _applicationPaths = applicationPaths;
+            _jsonSerializer = jsonSerializer;
+            _logger = logger;
+
+            ScheduledTasks = new IScheduledTask[] {};
+        }
+
+        /// <summary>
+        /// Cancels if running and queue.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        public void CancelIfRunningAndQueue<T>()
+                 where T : IScheduledTask
+        {
+            ScheduledTasks.OfType<T>().First().CancelIfRunning();
+            QueueScheduledTask<T>();
+        }
+
+        /// <summary>
+        /// Queues the scheduled task.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        public void QueueScheduledTask<T>()
+            where T : IScheduledTask
+        {
+            var scheduledTask = ScheduledTasks.OfType<T>().First();
+
+            QueueScheduledTask(scheduledTask);
+        }
+
+        /// <summary>
+        /// Queues the scheduled task.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        public void QueueScheduledTask(IScheduledTask task)
+        {
+            var type = task.GetType();
+
+            var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
+
+            lock (_taskQueue)
+            {
+                // If it's idle just execute immediately
+                if (scheduledTask.State == TaskState.Idle)
+                {
+                    scheduledTask.Execute();
+                    return;
+                }
+
+                if (!_taskQueue.Contains(type))
+                {
+                    _logger.Info("Queueing task {0}", type.Name);
+                    _taskQueue.Add(type);
+                }
+                else
+                {
+                    _logger.Info("Task already queued: {0}", type.Name);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Called when [task completed].
+        /// </summary>
+        /// <param name="task">The task.</param>
+        public void OnTaskCompleted(IScheduledTask task)
+        {
+            // Execute queued tasks
+            lock (_taskQueue)
+            {
+                var copy = _taskQueue.ToList();
+
+                foreach (var type in copy)
+                {
+                    var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
+
+                    if (scheduledTask.State == TaskState.Idle)
+                    {
+                        scheduledTask.Execute();
+
+                        _taskQueue.Remove(type);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Adds the tasks.
+        /// </summary>
+        /// <param name="tasks">The tasks.</param>
+        public void AddTasks(IEnumerable<IScheduledTask> tasks)
+        {
+            var myTasks = ScheduledTasks.ToList();
+
+            myTasks.AddRange(tasks);
+
+            ScheduledTasks = myTasks.ToArray();
+        }
+
+        /// <summary>
+        /// The _scheduled tasks configuration directory
+        /// </summary>
+        private string _scheduledTasksConfigurationDirectory;
+        /// <summary>
+        /// Gets the scheduled tasks configuration directory.
+        /// </summary>
+        /// <value>The scheduled tasks configuration directory.</value>
+        private string ScheduledTasksConfigurationDirectory
+        {
+            get
+            {
+                if (_scheduledTasksConfigurationDirectory == null)
+                {
+                    _scheduledTasksConfigurationDirectory = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
+
+                    if (!Directory.Exists(_scheduledTasksConfigurationDirectory))
+                    {
+                        Directory.CreateDirectory(_scheduledTasksConfigurationDirectory);
+                    }
+                }
+                return _scheduledTasksConfigurationDirectory;
+            }
+        }
+
+        /// <summary>
+        /// The _scheduled tasks data directory
+        /// </summary>
+        private string _scheduledTasksDataDirectory;
+        /// <summary>
+        /// Gets the scheduled tasks data directory.
+        /// </summary>
+        /// <value>The scheduled tasks data directory.</value>
+        private string ScheduledTasksDataDirectory
+        {
+            get
+            {
+                if (_scheduledTasksDataDirectory == null)
+                {
+                    _scheduledTasksDataDirectory = Path.Combine(_applicationPaths.DataPath, "ScheduledTasks");
+
+                    if (!Directory.Exists(_scheduledTasksDataDirectory))
+                    {
+                        Directory.CreateDirectory(_scheduledTasksDataDirectory);
+                    }
+                }
+                return _scheduledTasksDataDirectory;
+            }
+        }
+
+        /// <summary>
+        /// Gets the history file path.
+        /// </summary>
+        /// <value>The history file path.</value>
+        private string GetHistoryFilePath(IScheduledTask task)
+        {
+            return Path.Combine(ScheduledTasksDataDirectory, task.Id + ".js");
+        }
+
+        /// <summary>
+        /// Gets the configuration file path.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <returns>System.String.</returns>
+        private string GetConfigurationFilePath(IScheduledTask task)
+        {
+            return Path.Combine(ScheduledTasksConfigurationDirectory, task.Id + ".js");
+        }
+
+        /// <summary>
+        /// Called when [task completed].
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <param name="startTime">The start time.</param>
+        /// <param name="endTime">The end time.</param>
+        /// <param name="status">The status.</param>
+        public void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status)
+        {
+            var elapsedTime = endTime - startTime;
+
+            _logger.Info("{0} {1} after {2} minute(s) and {3} seconds", task.Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
+
+            var result = new TaskResult
+            {
+                StartTimeUtc = startTime,
+                EndTimeUtc = endTime,
+                Status = status,
+                Name = task.Name,
+                Id = task.Id
+            };
+
+            _jsonSerializer.SerializeToFile(result, GetHistoryFilePath(task));
+
+            //task.LastExecutionResult = result;
+        }
+
+        /// <summary>
+        /// Gets the last execution result.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <returns>TaskResult.</returns>
+        public TaskResult GetLastExecutionResult(IScheduledTask task)
+        {
+            return _jsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath(task));
+        }
+
+        /// <summary>
+        /// Loads the triggers.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+        public IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task)
+        {
+            try
+            {
+                return _jsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath(task))
+                .Select(ScheduledTaskHelpers.GetTrigger)
+                .ToList();
+            }
+            catch (IOException)
+            {
+                // File doesn't exist. No biggie. Return defaults.
+                return task.GetDefaultTriggers();
+            }
+        }
+
+        /// <summary>
+        /// Saves the triggers.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <param name="triggers">The triggers.</param>
+        public void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers)
+        {
+            _jsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath(task));
+        }
+
+        /// <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)
+        {
+            foreach (var task in ScheduledTasks)
+            {
+                task.Dispose();
+            }
+        }
+    }
+}

+ 3 - 2
MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs → MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
@@ -7,7 +8,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Common.ScheduledTasks.Tasks
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 {
     /// <summary>
     /// Deletes old cache files
@@ -29,7 +30,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am
 

+ 3 - 2
MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs → MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
@@ -7,7 +8,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Common.ScheduledTasks.Tasks
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 {
     /// <summary>
     /// Deletes old log files
@@ -29,7 +30,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am
 

+ 3 - 2
MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs → MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs

@@ -1,11 +1,12 @@
 using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Common.ScheduledTasks.Tasks
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 {
     /// <summary>
     /// Class ReloadLoggerFileTask
@@ -27,7 +28,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// Gets the default triggers.
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
             var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(0) }; //12am
 

+ 4 - 3
MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs → MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs

@@ -1,11 +1,12 @@
 using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Common.ScheduledTasks.Tasks
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 {
     /// <summary>
     /// Plugin Update Task
@@ -34,9 +35,9 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
-            return new BaseTaskTrigger[] { 
+            return new ITaskTrigger[] { 
             
                 // 1am
                 new DailyTrigger { TimeOfDay = TimeSpan.FromHours(1) },

+ 23 - 42
MediaBrowser.Common/Serialization/JsonSerializer.cs → MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs

@@ -1,13 +1,19 @@
-using System;
+using MediaBrowser.Model.Serialization;
+using System;
 using System.IO;
 
-namespace MediaBrowser.Common.Serialization
+namespace MediaBrowser.Common.Implementations.Serialization
 {
     /// <summary>
     /// Provides a wrapper around third party json serialization.
     /// </summary>
-    public class JsonSerializer
+    public class JsonSerializer : IJsonSerializer
     {
+        public JsonSerializer()
+        {
+            Configure();
+        }
+
         /// <summary>
         /// Serializes to stream.
         /// </summary>
@@ -15,7 +21,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="obj">The obj.</param>
         /// <param name="stream">The stream.</param>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public static void SerializeToStream<T>(T obj, Stream stream)
+        public void SerializeToStream<T>(T obj, Stream stream)
             where T : class
         {
             if (obj == null)
@@ -28,8 +34,6 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("stream");
             }
 
-            Configure();
-
             ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream);
         }
 
@@ -40,7 +44,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="obj">The obj.</param>
         /// <param name="file">The file.</param>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public static void SerializeToFile<T>(T obj, string file)
+        public void SerializeToFile<T>(T obj, string file)
             where T : class
         {
             if (obj == null)
@@ -53,8 +57,6 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("file");
             }
 
-            Configure();
-
             using (Stream stream = File.Open(file, FileMode.Create))
             {
                 SerializeToStream(obj, stream);
@@ -68,7 +70,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="file">The file.</param>
         /// <returns>System.Object.</returns>
         /// <exception cref="System.ArgumentNullException">type</exception>
-        public static object DeserializeFromFile(Type type, string file)
+        public object DeserializeFromFile(Type type, string file)
         {
             if (type == null)
             {
@@ -80,8 +82,6 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("file");
             }
 
-            Configure();
-
             using (Stream stream = File.OpenRead(file))
             {
                 return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream);
@@ -95,7 +95,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="file">The file.</param>
         /// <returns>``0.</returns>
         /// <exception cref="System.ArgumentNullException">file</exception>
-        public static T DeserializeFromFile<T>(string file)
+        public T DeserializeFromFile<T>(string file)
             where T : class
         {
             if (string.IsNullOrEmpty(file))
@@ -103,8 +103,6 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("file");
             }
 
-            Configure();
-
             using (Stream stream = File.OpenRead(file))
             {
                 return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream);
@@ -118,15 +116,13 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="stream">The stream.</param>
         /// <returns>``0.</returns>
         /// <exception cref="System.ArgumentNullException">stream</exception>
-        public static T DeserializeFromStream<T>(Stream stream)
+        public T DeserializeFromStream<T>(Stream stream)
         {
             if (stream == null)
             {
                 throw new ArgumentNullException("stream");
             }
 
-            Configure();
-
             return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream);
         }
 
@@ -137,15 +133,13 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="text">The text.</param>
         /// <returns>``0.</returns>
         /// <exception cref="System.ArgumentNullException">text</exception>
-        public static T DeserializeFromString<T>(string text)
+        public T DeserializeFromString<T>(string text)
         {
             if (string.IsNullOrEmpty(text))
             {
                 throw new ArgumentNullException("text");
             }
 
-            Configure();
-
             return ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(text);
         }
 
@@ -156,7 +150,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="type">The type.</param>
         /// <returns>System.Object.</returns>
         /// <exception cref="System.ArgumentNullException">stream</exception>
-        public static object DeserializeFromStream(Stream stream, Type type)
+        public object DeserializeFromStream(Stream stream, Type type)
         {
             if (stream == null)
             {
@@ -168,27 +162,17 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("type");
             }
 
-            Configure();
-
             return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream);
         }
 
-        /// <summary>
-        /// The _is configured
-        /// </summary>
-        private static bool _isConfigured;
         /// <summary>
         /// Configures this instance.
         /// </summary>
-        internal static void Configure()
+        private void Configure()
         {
-            if (!_isConfigured)
-            {
-                ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601;
-                ServiceStack.Text.JsConfig.ExcludeTypeInfo = true;
-                ServiceStack.Text.JsConfig.IncludeNullValues = false;
-                _isConfigured = true;
-            }
+            ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601;
+            ServiceStack.Text.JsConfig.ExcludeTypeInfo = true;
+            ServiceStack.Text.JsConfig.IncludeNullValues = false;
         }
 
         /// <summary>
@@ -198,7 +182,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="type">The type.</param>
         /// <returns>System.Object.</returns>
         /// <exception cref="System.ArgumentNullException">json</exception>
-        public static object DeserializeFromString(string json, Type type)
+        public object DeserializeFromString(string json, Type type)
         {
             if (string.IsNullOrEmpty(json))
             {
@@ -210,8 +194,6 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("type");
             }
 
-            Configure();
-
             return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type);
         }
 
@@ -222,7 +204,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="obj">The obj.</param>
         /// <returns>System.String.</returns>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public static string SerializeToString<T>(T obj)
+        public string SerializeToString<T>(T obj)
             where T : class
         {
             if (obj == null)
@@ -230,7 +212,6 @@ namespace MediaBrowser.Common.Serialization
                 throw new ArgumentNullException("obj");
             }
 
-            Configure();
             return ServiceStack.Text.JsonSerializer.SerializeToString(obj, obj.GetType());
         }
 
@@ -241,7 +222,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="obj">The obj.</param>
         /// <returns>System.Byte[][].</returns>
         /// <exception cref="System.ArgumentNullException">obj</exception>
-        public static byte[] SerializeToBytes<T>(T obj)
+        public byte[] SerializeToBytes<T>(T obj)
             where T : class
         {
             if (obj == null)

+ 7 - 6
MediaBrowser.Common/Serialization/DynamicProtobufSerializer.cs → MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs

@@ -1,22 +1,23 @@
-using ProtoBuf;
+using MediaBrowser.Model.Serialization;
+using ProtoBuf;
 using ProtoBuf.Meta;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 
-namespace MediaBrowser.Common.Serialization
+namespace MediaBrowser.Common.Implementations.Serialization
 {
     /// <summary>
     /// Creates a compiled protobuf serializer based on a set of assemblies
     /// </summary>
-    public class DynamicProtobufSerializer
+    public class ProtobufSerializer : IProtobufSerializer
     {
         /// <summary>
         /// Gets or sets the type model.
         /// </summary>
         /// <value>The type model.</value>
-        public TypeModel TypeModel { get; set; }
+        private TypeModel TypeModel { get; set; }
 
         /// <summary>
         /// Serializes to stream.
@@ -135,7 +136,7 @@ namespace MediaBrowser.Common.Serialization
         /// </summary>
         /// <returns>DynamicProtobufSerializer.</returns>
         /// <exception cref="System.ArgumentNullException">assemblies</exception>
-        public static DynamicProtobufSerializer Create(IEnumerable<Type> types)
+        public static ProtobufSerializer Create(IEnumerable<Type> types)
         {
             if (types == null)
             {
@@ -151,7 +152,7 @@ namespace MediaBrowser.Common.Serialization
                 model.Add(type, true);
             }
 
-            return new DynamicProtobufSerializer { TypeModel = model.Compile() };
+            return new ProtobufSerializer { TypeModel = model.Compile() };
         }
     }
 }

+ 12 - 84
MediaBrowser.Common/Serialization/XmlSerializer.cs → MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs

@@ -1,35 +1,21 @@
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.IO;
-using System.Linq;
 using System.Xml;
 
-namespace MediaBrowser.Common.Serialization
+namespace MediaBrowser.Common.Implementations.Serialization
 {
     /// <summary>
     /// Provides a wrapper around third party xml serialization.
     /// </summary>
-    public class XmlSerializer
+    public class XmlSerializer : IXmlSerializer
     {
-        /// <summary>
-        /// Serializes to writer.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="obj">The obj.</param>
-        /// <param name="writer">The writer.</param>
-        public static void SerializeToWriter<T>(T obj, XmlTextWriter writer)
-        {
-            writer.Formatting = Formatting.Indented;
-            var netSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
-            netSerializer.Serialize(writer, obj);
-        }
-
         /// <summary>
         /// Serializes to writer.
         /// </summary>
         /// <param name="obj">The obj.</param>
         /// <param name="writer">The writer.</param>
-        public static void SerializeToWriter(object obj, XmlTextWriter writer)
+        private void SerializeToWriter(object obj, XmlTextWriter writer)
         {
             writer.Formatting = Formatting.Indented;
             var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
@@ -42,7 +28,7 @@ namespace MediaBrowser.Common.Serialization
         /// <typeparam name="T"></typeparam>
         /// <param name="stream">The stream.</param>
         /// <returns>``0.</returns>
-        public static T DeserializeFromStream<T>(Stream stream)
+        public T DeserializeFromStream<T>(Stream stream)
         {
             using (var reader = new XmlTextReader(stream))
             {
@@ -58,7 +44,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="type">The type.</param>
         /// <param name="stream">The stream.</param>
         /// <returns>System.Object.</returns>
-        public static object DeserializeFromStream(Type type, Stream stream)
+        public object DeserializeFromStream(Type type, Stream stream)
         {
             using (var reader = new XmlTextReader(stream))
             {
@@ -73,7 +59,7 @@ namespace MediaBrowser.Common.Serialization
         /// </summary>
         /// <param name="obj">The obj.</param>
         /// <param name="stream">The stream.</param>
-        public static void SerializeToStream(object obj, Stream stream)
+        public void SerializeToStream(object obj, Stream stream)
         {
             using (var writer = new XmlTextWriter(stream, null))
             {
@@ -87,7 +73,7 @@ namespace MediaBrowser.Common.Serialization
         /// <typeparam name="T"></typeparam>
         /// <param name="file">The file.</param>
         /// <returns>``0.</returns>
-        public static T DeserializeFromFile<T>(string file)
+        public T DeserializeFromFile<T>(string file)
         {
             using (var stream = File.OpenRead(file))
             {
@@ -100,7 +86,7 @@ namespace MediaBrowser.Common.Serialization
         /// </summary>
         /// <param name="obj">The obj.</param>
         /// <param name="file">The file.</param>
-        public static void SerializeToFile(object obj, string file)
+        public void SerializeToFile(object obj, string file)
         {
             using (var stream = new FileStream(file, FileMode.Create))
             {
@@ -114,7 +100,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="type">The type.</param>
         /// <param name="file">The file.</param>
         /// <returns>System.Object.</returns>
-        public static object DeserializeFromFile(Type type, string file)
+        public object DeserializeFromFile(Type type, string file)
         {
             using (var stream = File.OpenRead(file))
             {
@@ -128,7 +114,7 @@ namespace MediaBrowser.Common.Serialization
         /// <param name="type">The type.</param>
         /// <param name="buffer">The buffer.</param>
         /// <returns>System.Object.</returns>
-        public static object DeserializeFromBytes(Type type, byte[] buffer)
+        public object DeserializeFromBytes(Type type, byte[] buffer)
         {
             using (var stream = new MemoryStream(buffer))
             {
@@ -141,7 +127,7 @@ namespace MediaBrowser.Common.Serialization
         /// </summary>
         /// <param name="obj">The obj.</param>
         /// <returns>System.Byte[][].</returns>
-        public static byte[] SerializeToBytes(object obj)
+        public byte[] SerializeToBytes(object obj)
         {
             using (var stream = new MemoryStream())
             {
@@ -150,63 +136,5 @@ namespace MediaBrowser.Common.Serialization
                 return stream.ToArray();
             }
         }
-
-        /// <summary>
-        /// Reads an xml configuration file from the file system
-        /// It will immediately re-serialize and save if new serialization data is available due to property changes
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <param name="path">The path.</param>
-        /// <param name="logger">The logger.</param>
-        /// <returns>System.Object.</returns>
-        public static object GetXmlConfiguration(Type type, string path, ILogger logger)
-        {
-            logger.Info("Loading {0} at {1}", type.Name, path);
-
-            object configuration;
-
-            byte[] buffer = null;
-
-            // Use try/catch to avoid the extra file system lookup using File.Exists
-            try
-            {
-                buffer = File.ReadAllBytes(path);
-
-                configuration = DeserializeFromBytes(type, buffer);
-            }
-            catch (FileNotFoundException)
-            {
-                configuration = Activator.CreateInstance(type);
-            }
-
-            // Take the object we just got and serialize it back to bytes
-            var newBytes = SerializeToBytes(configuration);
-
-            // If the file didn't exist before, or if something has changed, re-save
-            if (buffer == null || !buffer.SequenceEqual(newBytes))
-            {
-                logger.Info("Saving {0} to {1}", type.Name, path);
-
-                // Save it after load in case we got new items
-                File.WriteAllBytes(path, newBytes);
-            }
-
-            return configuration;
-        }
-
-        /// <summary>
-        /// Reads an xml configuration file from the file system
-        /// It will immediately save the configuration after loading it, just
-        /// in case there are new serializable properties
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="path">The path.</param>
-        /// <param name="logger">The logger.</param>
-        /// <returns>``0.</returns>
-        public static T GetXmlConfiguration<T>(string path, ILogger logger)
-            where T : class
-        {
-            return GetXmlConfiguration(typeof(T), path, logger) as T;
-        }
     }
 }

+ 5 - 0
MediaBrowser.Common.Implementations/packages.config

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" />
+  <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
+</packages>

+ 88 - 291
MediaBrowser.Common/Kernel/BaseKernel.cs

@@ -2,16 +2,14 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using System.Reflection;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -24,7 +22,7 @@ namespace MediaBrowser.Common.Kernel
     /// <typeparam name="TApplicationPathsType">The type of the T application paths type.</typeparam>
     public abstract class BaseKernel<TConfigurationType, TApplicationPathsType> : IDisposable, IKernel
         where TConfigurationType : BaseApplicationConfiguration, new()
-        where TApplicationPathsType : BaseApplicationPaths, new()
+        where TApplicationPathsType : IApplicationPaths
     {
         /// <summary>
         /// Occurs when [has pending restart changed].
@@ -129,7 +127,7 @@ namespace MediaBrowser.Common.Kernel
             get
             {
                 // Lazy load
-                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration<TConfigurationType>(ApplicationPaths.SystemConfigurationFilePath, Logger));
+                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => GetXmlConfiguration<TConfigurationType>(ApplicationPaths.SystemConfigurationFilePath));
                 return _configuration;
             }
             protected set
@@ -161,19 +159,6 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The application paths.</value>
         public TApplicationPathsType ApplicationPaths { get; private set; }
 
-        /// <summary>
-        /// The _failed assembly loads
-        /// </summary>
-        private readonly List<string> _failedPluginAssemblies = new List<string>();
-        /// <summary>
-        /// Gets the plugin assemblies that failed to load.
-        /// </summary>
-        /// <value>The failed assembly loads.</value>
-        public IEnumerable<string> FailedPluginAssemblies
-        {
-            get { return _failedPluginAssemblies; }
-        }
-
         /// <summary>
         /// Gets the list of currently loaded plugins
         /// </summary>
@@ -204,46 +189,6 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The rest services.</value>
         public IEnumerable<IRestfulService> RestServices { get; private set; }
 
-        /// <summary>
-        /// The disposable parts
-        /// </summary>
-        private readonly List<IDisposable> _disposableParts = new List<IDisposable>();
-
-        /// <summary>
-        /// The _protobuf serializer initialized
-        /// </summary>
-        private bool _protobufSerializerInitialized;
-        /// <summary>
-        /// The _protobuf serializer sync lock
-        /// </summary>
-        private object _protobufSerializerSyncLock = new object();
-        /// <summary>
-        /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection
-        /// </summary>
-        private DynamicProtobufSerializer _protobufSerializer;
-        /// <summary>
-        /// Gets the protobuf serializer.
-        /// </summary>
-        /// <value>The protobuf serializer.</value>
-        public DynamicProtobufSerializer ProtobufSerializer
-        {
-            get
-            {
-                // Lazy load
-                LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => DynamicProtobufSerializer.Create(AllTypes));
-                return _protobufSerializer;
-            }
-            private set
-            {
-                _protobufSerializer = value;
-
-                if (value == null)
-                {
-                    _protobufSerializerInitialized = false;
-                }
-            }
-        }
-
         /// <summary>
         /// Gets the UDP server port number.
         /// This can't be configurable because then the user would have to configure their client to discover the server.
@@ -301,42 +246,40 @@ namespace MediaBrowser.Common.Kernel
         protected IApplicationHost ApplicationHost { get; private set; }
 
         /// <summary>
-        /// Gets or sets the task manager.
-        /// </summary>
-        /// <value>The task manager.</value>
-        protected ITaskManager TaskManager { get; set; }
-
-        /// <summary>
-        /// Gets the assemblies.
+        /// The _XML serializer
         /// </summary>
-        /// <value>The assemblies.</value>
-        protected Assembly[] Assemblies { get; private set; }
-
-        /// <summary>
-        /// Gets all types.
-        /// </summary>
-        /// <value>All types.</value>
-        public Type[] AllTypes { get; private set; }
+        private readonly IXmlSerializer _xmlSerializer;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseKernel{TApplicationPathsType}" /> class.
         /// </summary>
         /// <param name="appHost">The app host.</param>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="xmlSerializer">The XML serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">isoManager</exception>
-        protected BaseKernel(IApplicationHost appHost, ILogger logger)
+        protected BaseKernel(IApplicationHost appHost, TApplicationPathsType appPaths, IXmlSerializer xmlSerializer, ILogger logger)
         {
             if (appHost == null)
             {
                 throw new ArgumentNullException("appHost");
             }
-
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+            if (xmlSerializer == null)
+            {
+                throw new ArgumentNullException("xmlSerializer");
+            }
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
             }
 
+            ApplicationPaths = appPaths;
             ApplicationHost = appHost;
+            _xmlSerializer = xmlSerializer;
             Logger = logger;
         }
 
@@ -344,14 +287,12 @@ namespace MediaBrowser.Common.Kernel
         /// Initializes the Kernel
         /// </summary>
         /// <returns>Task.</returns>
-        public async Task Init()
+        public Task Init()
         {
-            ApplicationPaths = new TApplicationPathsType();
-
             IsFirstRun = !File.Exists(ApplicationPaths.SystemConfigurationFilePath);
 
             // Performs initializations that can be reloaded at anytime
-            await Reload().ConfigureAwait(false);
+            return Reload();
         }
 
         /// <summary>
@@ -377,7 +318,6 @@ namespace MediaBrowser.Common.Kernel
         {
             // Set these to null so that they can be lazy loaded again
             Configuration = null;
-            ProtobufSerializer = null;
 
             ReloadLogger();
 
@@ -388,14 +328,12 @@ namespace MediaBrowser.Common.Kernel
 
             await OnConfigurationLoaded().ConfigureAwait(false);
 
-            DisposeTaskManager();
-            TaskManager = new TaskManager(Logger);
+            FindParts();
 
-            Logger.Info("Loading Plugins");
-            await ReloadComposableParts().ConfigureAwait(false);
+            await OnComposablePartsLoaded().ConfigureAwait(false);
 
             DisposeTcpManager();
-            TcpManager = new TcpManager(ApplicationHost, this, ApplicationHost.Resolve<INetworkManager>(), Logger);
+            TcpManager = (TcpManager)ApplicationHost.CreateInstance(typeof(TcpManager));
         }
 
         /// <summary>
@@ -417,184 +355,14 @@ namespace MediaBrowser.Common.Kernel
             OnLoggerLoaded();
         }
 
-        /// <summary>
-        /// Uses MEF to locate plugins
-        /// Subclasses can use this to locate types within plugins
-        /// </summary>
-        /// <returns>Task.</returns>
-        private async Task ReloadComposableParts()
-        {
-            _failedPluginAssemblies.Clear();
-
-            DisposeComposableParts();
-
-            Assemblies = GetComposablePartAssemblies().ToArray();
-
-            AllTypes = Assemblies.SelectMany(GetTypes).ToArray();
-
-            ComposeParts(AllTypes);
-
-            await OnComposablePartsLoaded().ConfigureAwait(false);
-        }
-
-        /// <summary>
-        /// Composes the parts.
-        /// </summary>
-        /// <param name="allTypes">All types.</param>
-        private void ComposeParts(IEnumerable<Type> allTypes)
-        {
-            var concreteTypes = allTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
-
-            RegisterExportedValues();
-
-            FindParts(concreteTypes);
-        }
-
         /// <summary>
         /// Composes the parts with ioc container.
         /// </summary>
-        /// <param name="allTypes">All types.</param>
-        protected virtual void FindParts(Type[] allTypes)
-        {
-            RestServices = GetExports<IRestfulService>(allTypes);
-            WebSocketListeners = GetExports<IWebSocketListener>(allTypes);
-            Plugins = GetExports<IPlugin>(allTypes);
-
-            var tasks = GetExports<IScheduledTask>(allTypes, false);
-
-            TaskManager.AddTasks(tasks);
-        }
-
-        /// <summary>
-        /// Gets the exports.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="allTypes">All types.</param>
-        /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
-        /// <returns>IEnumerable{``0}.</returns>
-        protected IEnumerable<T> GetExports<T>(Type[] allTypes, bool manageLiftime = true)
-        {
-            var currentType = typeof(T);
-
-            Logger.Info("Composing instances of " + currentType.Name);
-
-            var parts = allTypes.Where(currentType.IsAssignableFrom).Select(Instantiate).Cast<T>().ToArray();
-
-            if (manageLiftime)
-            {
-                _disposableParts.AddRange(parts.OfType<IDisposable>());
-            }
-
-            return parts;
-        }
-
-        /// <summary>
-        /// Instantiates the specified type.
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <returns>System.Object.</returns>
-        private object Instantiate(Type type)
-        {
-            return ApplicationHost.CreateInstance(type);
-        }
-
-        /// <summary>
-        /// Composes the exported values.
-        /// </summary>
-        /// <param name="container">The container.</param>
-        protected virtual void RegisterExportedValues()
+        protected virtual void FindParts()
         {
-            ApplicationHost.RegisterSingleInstance<IKernel>(this);
-            ApplicationHost.RegisterSingleInstance(TaskManager);
-        }
-
-        /// <summary>
-        /// Gets the composable part assemblies.
-        /// </summary>
-        /// <returns>IEnumerable{Assembly}.</returns>
-        protected virtual IEnumerable<Assembly> GetComposablePartAssemblies()
-        {
-            // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
-            // This will prevent the .dll file from getting locked, and allow us to replace it when needed
-            var pluginAssemblies = Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
-                .Select(file =>
-                {
-                    try
-                    {
-                        return Assembly.Load(File.ReadAllBytes((file)));
-                    }
-                    catch (Exception ex)
-                    {
-                        _failedPluginAssemblies.Add(file);
-                        Logger.ErrorException("Error loading {0}", ex, file);
-                        return null;
-                    }
-
-                }).Where(a => a != null);
-
-            foreach (var pluginAssembly in pluginAssemblies)
-            {
-                yield return pluginAssembly;
-            }
-
-            var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
-            var corePluginDirectory = Path.Combine(runningDirectory, "CorePlugins");
-
-            // This will prevent the .dll file from getting locked, and allow us to replace it when needed
-            pluginAssemblies = Directory.EnumerateFiles(corePluginDirectory, "*.dll", SearchOption.TopDirectoryOnly)
-                .Select(file =>
-                {
-                    try
-                    {
-                        return Assembly.Load(File.ReadAllBytes((file)));
-                    }
-                    catch (Exception ex)
-                    {
-                        _failedPluginAssemblies.Add(file);
-                        Logger.ErrorException("Error loading {0}", ex, file);
-                        return null;
-                    }
-
-                }).Where(a => a != null);
-
-            foreach (var pluginAssembly in pluginAssemblies)
-            {
-                yield return pluginAssembly;
-            }
-
-            // Include composable parts in the Model assembly 
-            yield return typeof(SystemInfo).Assembly;
-
-            // Include composable parts in the Common assembly 
-            yield return Assembly.GetExecutingAssembly();
-
-            // Include composable parts in the subclass assembly
-            yield return GetType().Assembly;
-        }
-
-        /// <summary>
-        /// Gets a list of types within an assembly
-        /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
-        /// </summary>
-        /// <param name="assembly">The assembly.</param>
-        /// <returns>IEnumerable{Type}.</returns>
-        /// <exception cref="System.ArgumentNullException">assembly</exception>
-        private static IEnumerable<Type> GetTypes(Assembly assembly)
-        {
-            if (assembly == null)
-            {
-                throw new ArgumentNullException("assembly");
-            }
-
-            try
-            {
-                return assembly.GetTypes();
-            }
-            catch (ReflectionTypeLoadException ex)
-            {
-                // If it fails we can still get a list of the Types it was able to resolve
-                return ex.Types.Where(t => t != null);
-            }
+            RestServices = ApplicationHost.GetExports<IRestfulService>();
+            WebSocketListeners = ApplicationHost.GetExports<IWebSocketListener>();
+            Plugins = ApplicationHost.GetExports<IPlugin>();
         }
 
         /// <summary>
@@ -612,7 +380,7 @@ namespace MediaBrowser.Common.Kernel
 
                     try
                     {
-                        plugin.Initialize(this, Logger);
+                        plugin.Initialize(this, _xmlSerializer, Logger);
 
                         Logger.Info("{0} {1} initialized.", plugin.Name, plugin.Version);
                     }
@@ -654,12 +422,7 @@ namespace MediaBrowser.Common.Kernel
             if (dispose)
             {
                 DisposeTcpManager();
-                DisposeTaskManager();
                 DisposeHttpManager();
-
-                DisposeComposableParts();
-
-                _disposableParts.Clear();
             }
         }
 
@@ -675,18 +438,6 @@ namespace MediaBrowser.Common.Kernel
             }
         }
 
-        /// <summary>
-        /// Disposes the task manager.
-        /// </summary>
-        private void DisposeTaskManager()
-        {
-            if (TaskManager != null)
-            {
-                TaskManager.Dispose();
-                TaskManager = null;
-            }
-        }
-
         /// <summary>
         /// Disposes the HTTP manager.
         /// </summary>
@@ -699,17 +450,6 @@ namespace MediaBrowser.Common.Kernel
             }
         }
 
-        /// <summary>
-        /// Disposes all objects gathered through MEF composable parts
-        /// </summary>
-        protected virtual void DisposeComposableParts()
-        {
-            foreach (var part in _disposableParts)
-            {
-                part.Dispose();
-            }
-        }
-
         /// <summary>
         /// Gets the current application version
         /// </summary>
@@ -761,7 +501,7 @@ namespace MediaBrowser.Common.Kernel
                 IsNetworkDeployed = ApplicationHost.CanSelfUpdate,
                 WebSocketPortNumber = TcpManager.WebSocketPortNumber,
                 SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket,
-                FailedPluginAssemblies = FailedPluginAssemblies.ToArray()
+                FailedPluginAssemblies = ApplicationHost.FailedAssemblies.ToArray()
             };
         }
 
@@ -777,7 +517,7 @@ namespace MediaBrowser.Common.Kernel
         {
             lock (_configurationSaveLock)
             {
-                XmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath);
+                _xmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath);
             }
 
             OnConfigurationUpdated();
@@ -787,7 +527,7 @@ namespace MediaBrowser.Common.Kernel
         /// Gets the application paths.
         /// </summary>
         /// <value>The application paths.</value>
-        BaseApplicationPaths IKernel.ApplicationPaths
+        IApplicationPaths IKernel.ApplicationPaths
         {
             get { return ApplicationPaths; }
         }
@@ -798,6 +538,63 @@ namespace MediaBrowser.Common.Kernel
         BaseApplicationConfiguration IKernel.Configuration
         {
             get { return Configuration; }
+        }		        
+        
+        /// <summary>
+        /// Reads an xml configuration file from the file system
+        /// It will immediately re-serialize and save if new serialization data is available due to property changes
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="path">The path.</param>
+        /// <returns>System.Object.</returns>
+        public object GetXmlConfiguration(Type type, string path)
+        {
+            Logger.Info("Loading {0} at {1}", type.Name, path);
+
+            object configuration;
+
+            byte[] buffer = null;
+
+            // Use try/catch to avoid the extra file system lookup using File.Exists
+            try
+            {
+                buffer = File.ReadAllBytes(path);
+
+                configuration = _xmlSerializer.DeserializeFromBytes(type, buffer);
+            }
+            catch (FileNotFoundException)
+            {
+                configuration = ApplicationHost.CreateInstance(type);
+            }
+
+            // Take the object we just got and serialize it back to bytes
+            var newBytes = _xmlSerializer.SerializeToBytes(configuration);
+
+            // If the file didn't exist before, or if something has changed, re-save
+            if (buffer == null || !buffer.SequenceEqual(newBytes))
+            {
+                Logger.Info("Saving {0} to {1}", type.Name, path);
+
+                // Save it after load in case we got new items
+                File.WriteAllBytes(path, newBytes);
+            }
+
+            return configuration;
+        }
+
+
+        /// <summary>
+        /// Reads an xml configuration file from the file system
+        /// It will immediately save the configuration after loading it, just
+        /// in case there are new serializable properties
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="path">The path.</param>
+        /// <returns>``0.</returns>
+        private T GetXmlConfiguration<T>(string path)
+            where T : class
+        {
+            return GetXmlConfiguration(typeof(T), path) as T;
         }
     }
 }

+ 21 - 0
MediaBrowser.Common/Kernel/IApplicationHost.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Model.Updates;
 using System;
+using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -32,6 +33,26 @@ namespace MediaBrowser.Common.Kernel
         /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
         bool CanSelfUpdate { get; }
 
+        /// <summary>
+        /// Gets the failed assemblies.
+        /// </summary>
+        /// <value>The failed assemblies.</value>
+        IEnumerable<string> FailedAssemblies { get; }
+
+        /// <summary>
+        /// Gets all concrete types.
+        /// </summary>
+        /// <value>All concrete types.</value>
+        Type[] AllConcreteTypes { get; }
+
+        /// <summary>
+        /// Gets the exports.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
+        /// <returns>IEnumerable{``0}.</returns>
+        IEnumerable<T> GetExports<T>(bool manageLiftime = true);
+
         /// <summary>
         /// Checks for update.
         /// </summary>

+ 76 - 0
MediaBrowser.Common/Kernel/IApplicationPaths.cs

@@ -0,0 +1,76 @@
+
+namespace MediaBrowser.Common.Kernel
+{
+    /// <summary>
+    /// Interface IApplicationPaths
+    /// </summary>
+    public interface IApplicationPaths
+    {
+        /// <summary>
+        /// Gets the path to the program data folder
+        /// </summary>
+        /// <value>The program data path.</value>
+        string ProgramDataPath { get; }
+
+        /// <summary>
+        /// Gets the folder path to the data directory
+        /// </summary>
+        /// <value>The data directory.</value>
+        string DataPath { get; }
+
+        /// <summary>
+        /// Gets the image cache path.
+        /// </summary>
+        /// <value>The image cache path.</value>
+        string ImageCachePath { get; }
+
+        /// <summary>
+        /// Gets the path to the plugin directory
+        /// </summary>
+        /// <value>The plugins path.</value>
+        string PluginsPath { get; }
+
+        /// <summary>
+        /// Gets the path to the plugin configurations directory
+        /// </summary>
+        /// <value>The plugin configurations path.</value>
+        string PluginConfigurationsPath { get; }
+
+        /// <summary>
+        /// Gets the path to where temporary update files will be stored
+        /// </summary>
+        /// <value>The plugin configurations path.</value>
+        string TempUpdatePath { get; }
+
+        /// <summary>
+        /// Gets the path to the log directory
+        /// </summary>
+        /// <value>The log directory path.</value>
+        string LogDirectoryPath { get; }
+
+        /// <summary>
+        /// Gets the path to the application configuration root directory
+        /// </summary>
+        /// <value>The configuration directory path.</value>
+        string ConfigurationDirectoryPath { get; }
+
+        /// <summary>
+        /// Gets the path to the system configuration file
+        /// </summary>
+        /// <value>The system configuration file path.</value>
+        string SystemConfigurationFilePath { get; }
+
+        /// <summary>
+        /// Gets the folder path to the cache directory
+        /// </summary>
+        /// <value>The cache directory.</value>
+        string CachePath { get; }
+
+        /// <summary>
+        /// Gets the folder path to the temp directory within the cache folder
+        /// </summary>
+        /// <value>The temp directory.</value>
+        string TempDirectory { get; }
+    }
+
+}

+ 9 - 8
MediaBrowser.Common/Kernel/IKernel.cs

@@ -1,6 +1,5 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.System;
 using System;
@@ -18,7 +17,7 @@ namespace MediaBrowser.Common.Kernel
         /// Gets the application paths.
         /// </summary>
         /// <value>The application paths.</value>
-        BaseApplicationPaths ApplicationPaths { get; }
+        IApplicationPaths ApplicationPaths { get; }
 
         /// <summary>
         /// Gets the configuration.
@@ -32,12 +31,6 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The kernel context.</value>
         KernelContext KernelContext { get; }
 
-        /// <summary>
-        /// Gets the protobuf serializer.
-        /// </summary>
-        /// <value>The protobuf serializer.</value>
-        DynamicProtobufSerializer ProtobufSerializer { get; }
-
         /// <summary>
         /// Inits this instance.
         /// </summary>
@@ -156,5 +149,13 @@ namespace MediaBrowser.Common.Kernel
         /// Notifies the pending restart.
         /// </summary>
         void NotifyPendingRestart();
+
+        /// <summary>
+        /// Gets the XML configuration.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="path">The path.</param>
+        /// <returns>System.Object.</returns>
+        object GetXmlConfiguration(Type type, string path);
     }
 }

+ 17 - 4
MediaBrowser.Common/Kernel/TcpManager.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Logging;
 using System;
@@ -14,6 +13,7 @@ using System.Reflection;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Common.Kernel
 {
@@ -35,6 +35,12 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The HTTP server.</value>
         private IHttpServer HttpServer { get; set; }
 
+        /// <summary>
+        /// Gets or sets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private IJsonSerializer _jsonSerializer;
+        
         /// <summary>
         /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it
         /// </summary>
@@ -96,8 +102,10 @@ namespace MediaBrowser.Common.Kernel
         /// <param name="applicationHost">The application host.</param>
         /// <param name="kernel">The kernel.</param>
         /// <param name="networkManager">The network manager.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
-        public TcpManager(IApplicationHost applicationHost, IKernel kernel, INetworkManager networkManager, ILogger logger)
+        /// <exception cref="System.ArgumentNullException">applicationHost</exception>
+        public TcpManager(IApplicationHost applicationHost, IKernel kernel, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger)
         {
             if (applicationHost == null)
             {
@@ -111,12 +119,17 @@ namespace MediaBrowser.Common.Kernel
             {
                 throw new ArgumentNullException("networkManager");
             }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
             }
 
             _logger = logger;
+            _jsonSerializer = jsonSerializer;
             _kernel = kernel;
             _applicationHost = applicationHost;
             _networkManager = networkManager;
@@ -203,7 +216,7 @@ namespace MediaBrowser.Common.Kernel
         /// <param name="e">The <see cref="WebSocketConnectEventArgs" /> instance containing the event data.</param>
         void HttpServer_WebSocketConnected(object sender, WebSocketConnectEventArgs e)
         {
-            var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, ProcessWebSocketMessageReceived, _logger);
+            var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, ProcessWebSocketMessageReceived, _jsonSerializer, _logger);
 
             _webSocketConnections.Add(connection);
         }
@@ -342,7 +355,7 @@ namespace MediaBrowser.Common.Kernel
                 _logger.Info("Sending web socket message {0}", messageType);
 
                 var message = new WebSocketMessage<T> { MessageType = messageType, Data = dataFunction() };
-                var bytes = JsonSerializer.SerializeToBytes(message);
+                var bytes = _jsonSerializer.SerializeToBytes(message);
 
                 var tasks = connections.Select(s => Task.Run(() =>
                 {

+ 2 - 17
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -38,10 +38,6 @@
     </ApplicationIcon>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="protobuf-net, Version=2.0.0.621, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath>
-    </Reference>
     <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath>
@@ -75,14 +71,12 @@
       <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
     </Reference>
     <Reference Include="System" />
-    <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Net.Http.WebRequest" />
     <Reference Include="System.Web" />
     <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\SharedVersion.cs">
@@ -98,8 +92,8 @@
     <Compile Include="IO\IIsoMount.cs" />
     <Compile Include="IO\ProgressStream.cs" />
     <Compile Include="IO\StreamDefaults.cs" />
-    <Compile Include="Kernel\BaseApplicationPaths.cs" />
     <Compile Include="Kernel\BasePeriodicWebSocketListener.cs" />
+    <Compile Include="Kernel\IApplicationPaths.cs" />
     <Compile Include="Kernel\IWebSocketListener.cs" />
     <Compile Include="Kernel\IApplicationHost.cs" />
     <Compile Include="Kernel\IKernel.cs" />
@@ -116,7 +110,6 @@
     <Compile Include="Net\IWebSocket.cs" />
     <Compile Include="Net\IWebSocketServer.cs" />
     <Compile Include="Net\MimeTypes.cs" />
-    <Compile Include="Net\NativeWebSocket.cs" />
     <Compile Include="Net\UdpMessageReceivedEventArgs.cs" />
     <Compile Include="Net\WebSocketConnectEventArgs.cs" />
     <Compile Include="Net\WebSocketConnection.cs" />
@@ -130,26 +123,18 @@
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
     <Compile Include="ScheduledTasks\ITaskManager.cs" />
-    <Compile Include="ScheduledTasks\TaskManager.cs" />
-    <Compile Include="ScheduledTasks\Tasks\ReloadLoggerTask.cs" />
+    <Compile Include="ScheduledTasks\ITaskTrigger.cs" />
     <Compile Include="ScheduledTasks\ScheduledTaskHelpers.cs" />
     <Compile Include="ScheduledTasks\StartupTrigger.cs" />
     <Compile Include="ScheduledTasks\SystemEventTrigger.cs" />
-    <Compile Include="ScheduledTasks\Tasks\SystemUpdateTask.cs" />
-    <Compile Include="Serialization\DynamicProtobufSerializer.cs" />
-    <Compile Include="Serialization\JsonSerializer.cs" />
     <Compile Include="Kernel\BaseKernel.cs" />
     <Compile Include="Kernel\KernelContext.cs" />
     <Compile Include="Net\Handlers\BaseHandler.cs" />
     <Compile Include="Net\Handlers\BaseSerializationHandler.cs" />
     <Compile Include="Plugins\BasePlugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Serialization\XmlSerializer.cs" />
     <Compile Include="ScheduledTasks\BaseScheduledTask.cs" />
-    <Compile Include="ScheduledTasks\BaseTaskTrigger.cs" />
     <Compile Include="ScheduledTasks\DailyTrigger.cs" />
-    <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
-    <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
     <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
     <Compile Include="ScheduledTasks\IScheduledTask.cs" />
     <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />

+ 9 - 10
MediaBrowser.Common/Net/Handlers/BaseSerializationHandler.cs

@@ -1,6 +1,5 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Serialization;
 using System;
 using System.IO;
 using System.Threading.Tasks;
@@ -104,15 +103,15 @@ namespace MediaBrowser.Common.Net.Handlers
         {
             return Task.Run(() =>
             {
-                switch (SerializationFormat)
-                {
-                    case SerializationFormat.Protobuf:
-                        Kernel.ProtobufSerializer.SerializeToStream(_objectToSerialize, stream);
-                        break;
-                    default:
-                        JsonSerializer.SerializeToStream(_objectToSerialize, stream);
-                        break;
-                }
+                //switch (SerializationFormat)
+                //{
+                //    case SerializationFormat.Protobuf:
+                //        Kernel.ProtobufSerializer.SerializeToStream(_objectToSerialize, stream);
+                //        break;
+                //    default:
+                //        JsonSerializer.SerializeToStream(_objectToSerialize, stream);
+                //        break;
+                //}
             });
         }
     }

+ 1 - 1
MediaBrowser.Common/Net/IWebSocket.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.Common.Net
         /// Gets or sets the receive action.
         /// </summary>
         /// <value>The receive action.</value>
-        Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; }
+        Action<byte[]> OnReceiveDelegate { get; set; }
 
         /// <summary>
         /// Sends the async.

+ 26 - 7
MediaBrowser.Common/Net/WebSocketConnection.cs

@@ -1,7 +1,7 @@
-using MediaBrowser.Common.Serialization;
+using System.IO;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
-using System.Net;
 using System.Net.WebSockets;
 using System.Threading;
 using System.Threading.Tasks;
@@ -38,14 +38,21 @@ namespace MediaBrowser.Common.Net
         /// </summary>
         private readonly ILogger _logger;
 
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
         /// </summary>
         /// <param name="socket">The socket.</param>
         /// <param name="remoteEndPoint">The remote end point.</param>
         /// <param name="receiveAction">The receive action.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">socket</exception>
-        public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, ILogger logger)
+        public WebSocketConnection(IWebSocket socket, string remoteEndPoint, Action<WebSocketMessageInfo> receiveAction, IJsonSerializer jsonSerializer, ILogger logger)
         {
             if (socket == null)
             {
@@ -59,11 +66,16 @@ namespace MediaBrowser.Common.Net
             {
                 throw new ArgumentNullException("receiveAction");
             }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
             }
 
+            _jsonSerializer = jsonSerializer;
             _socket = socket;
             _socket.OnReceiveDelegate = info => OnReceive(info, receiveAction);
             RemoteEndPoint = remoteEndPoint;
@@ -73,12 +85,19 @@ namespace MediaBrowser.Common.Net
         /// <summary>
         /// Called when [receive].
         /// </summary>
-        /// <param name="info">The info.</param>
+        /// <param name="bytes">The bytes.</param>
         /// <param name="callback">The callback.</param>
-        private void OnReceive(WebSocketMessageInfo info, Action<WebSocketMessageInfo> callback)
+        private void OnReceive(byte[] bytes, Action<WebSocketMessageInfo> callback)
         {
             try
             {
+                WebSocketMessageInfo info;
+
+                using (var memoryStream = new MemoryStream(bytes))
+                {
+                    info = _jsonSerializer.DeserializeFromStream<WebSocketMessageInfo>(memoryStream);
+                }
+
                 info.Connection = this;
 
                 callback(info);
@@ -103,8 +122,8 @@ namespace MediaBrowser.Common.Net
             {
                 throw new ArgumentNullException("message");
             }
-            
-            var bytes = JsonSerializer.SerializeToBytes(message);
+
+            var bytes = _jsonSerializer.SerializeToBytes(message);
 
             return SendAsync(bytes, cancellationToken);
         }

+ 17 - 5
MediaBrowser.Common/Plugins/BasePlugin.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Plugins;
 using System;
@@ -7,6 +6,7 @@ using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Threading;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Common.Plugins
 {
@@ -188,7 +188,7 @@ namespace MediaBrowser.Common.Plugins
             get
             {
                 // Lazy load
-                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath, Logger) as TConfigurationType);
+                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => Kernel.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath) as TConfigurationType);
                 return _configuration;
             }
             protected set
@@ -269,26 +269,38 @@ namespace MediaBrowser.Common.Plugins
         /// <value>The logger.</value>
         public ILogger Logger { get; private set; }
 
+        /// <summary>
+        /// Gets the XML serializer.
+        /// </summary>
+        /// <value>The XML serializer.</value>
+        protected IXmlSerializer XmlSerializer { get; private set; }
+
         /// <summary>
         /// Starts the plugin.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
+        /// <param name="xmlSerializer">The XML serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">kernel</exception>
-        public void Initialize(IKernel kernel, ILogger logger)
+        public void Initialize(IKernel kernel, IXmlSerializer xmlSerializer, ILogger logger)
         {
             if (kernel == null)
             {
                 throw new ArgumentNullException("kernel");
             }
 
+            if (xmlSerializer == null)
+            {
+                throw new ArgumentNullException("xmlSerializer");
+            }
+            
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
             }
-            
+
+            XmlSerializer = xmlSerializer;
             Logger = logger;
-            
             Kernel = kernel;
 
             if (kernel.KernelContext == KernelContext.Server)

+ 3 - 1
MediaBrowser.Common/Plugins/IPlugin.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
 using System;
 
 namespace MediaBrowser.Common.Plugins
@@ -107,9 +108,10 @@ namespace MediaBrowser.Common.Plugins
         /// Starts the plugin.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
+        /// <param name="xmlSerializer">The XML serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">kernel</exception>
-        void Initialize(IKernel kernel, ILogger logger);
+        void Initialize(IKernel kernel, IXmlSerializer xmlSerializer, ILogger logger);
 
         /// <summary>
         /// Disposes the plugins. Undos all actions performed during Init.

+ 19 - 121
MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs

@@ -1,6 +1,5 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Tasks;
 using System;
@@ -90,7 +89,7 @@ namespace MediaBrowser.Common.ScheduledTasks
                 {
                     try
                     {
-                        return JsonSerializer.DeserializeFromFile<TaskResult>(HistoryFilePath);
+                        return TaskManager.GetLastExecutionResult(this);
                     }
                     catch (IOException)
                     {
@@ -109,74 +108,6 @@ namespace MediaBrowser.Common.ScheduledTasks
             }
         }
 
-        /// <summary>
-        /// The _scheduled tasks data directory
-        /// </summary>
-        private string _scheduledTasksDataDirectory;
-        /// <summary>
-        /// Gets the scheduled tasks data directory.
-        /// </summary>
-        /// <value>The scheduled tasks data directory.</value>
-        private string ScheduledTasksDataDirectory
-        {
-            get
-            {
-                if (_scheduledTasksDataDirectory == null)
-                {
-                    _scheduledTasksDataDirectory = Path.Combine(Kernel.ApplicationPaths.DataPath, "ScheduledTasks");
-
-                    if (!Directory.Exists(_scheduledTasksDataDirectory))
-                    {
-                        Directory.CreateDirectory(_scheduledTasksDataDirectory);
-                    }
-                }
-                return _scheduledTasksDataDirectory;
-            }
-        }
-
-        /// <summary>
-        /// The _scheduled tasks configuration directory
-        /// </summary>
-        private string _scheduledTasksConfigurationDirectory;
-        /// <summary>
-        /// Gets the scheduled tasks configuration directory.
-        /// </summary>
-        /// <value>The scheduled tasks configuration directory.</value>
-        private string ScheduledTasksConfigurationDirectory
-        {
-            get
-            {
-                if (_scheduledTasksConfigurationDirectory == null)
-                {
-                    _scheduledTasksConfigurationDirectory = Path.Combine(Kernel.ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
-
-                    if (!Directory.Exists(_scheduledTasksConfigurationDirectory))
-                    {
-                        Directory.CreateDirectory(_scheduledTasksConfigurationDirectory);
-                    }
-                }
-                return _scheduledTasksConfigurationDirectory;
-            }
-        }
-
-        /// <summary>
-        /// Gets the configuration file path.
-        /// </summary>
-        /// <value>The configuration file path.</value>
-        private string ConfigurationFilePath
-        {
-            get { return Path.Combine(ScheduledTasksConfigurationDirectory, Id + ".js"); }
-        }
-
-        /// <summary>
-        /// Gets the history file path.
-        /// </summary>
-        /// <value>The history file path.</value>
-        private string HistoryFilePath
-        {
-            get { return Path.Combine(ScheduledTasksDataDirectory, Id + ".js"); }
-        }
-
         /// <summary>
         /// Gets the current cancellation token
         /// </summary>
@@ -217,7 +148,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// The _triggers
         /// </summary>
-        private IEnumerable<BaseTaskTrigger> _triggers;
+        private IEnumerable<ITaskTrigger> _triggers;
         /// <summary>
         /// The _triggers initialized
         /// </summary>
@@ -231,24 +162,11 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// </summary>
         /// <value>The triggers.</value>
         /// <exception cref="System.ArgumentNullException">value</exception>
-        public IEnumerable<BaseTaskTrigger> Triggers
+        public IEnumerable<ITaskTrigger> Triggers
         {
             get
             {
-                LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () =>
-                {
-                    try
-                    {
-                        return JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(ConfigurationFilePath)
-                            .Select(ScheduledTaskHelpers.GetTrigger)
-                            .ToList();
-                    }
-                    catch (IOException)
-                    {
-                        // File doesn't exist. No biggie. Return defaults.
-                        return GetDefaultTriggers();
-                    }
-                });
+                LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, () => TaskManager.LoadTriggers(this));
 
                 return _triggers;
             }
@@ -271,7 +189,7 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 ReloadTriggerEvents(false);
 
-                JsonSerializer.SerializeToFile(_triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), ConfigurationFilePath);
+                TaskManager.SaveTriggers(this, _triggers);
             }
         }
 
@@ -279,7 +197,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected abstract IEnumerable<BaseTaskTrigger> GetDefaultTriggers();
+        public abstract IEnumerable<ITaskTrigger> GetDefaultTriggers();
 
         /// <summary>
         /// Returns the task to be executed
@@ -314,6 +232,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// The _id
         /// </summary>
         private Guid? _id;
+
         /// <summary>
         /// Gets the unique id.
         /// </summary>
@@ -352,13 +271,19 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// </summary>
         /// <param name="sender">The source of the event.</param>
         /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
-        void trigger_Triggered(object sender, EventArgs e)
+        async void trigger_Triggered(object sender, EventArgs e)
         {
-            var trigger = (BaseTaskTrigger)sender;
+            var trigger = (ITaskTrigger)sender;
 
             Logger.Info("{0} fired for task: {1}", trigger.GetType().Name, Name);
 
+            trigger.Stop();
+
             TaskManager.QueueScheduledTask(this);
+
+            await Task.Delay(1000).ConfigureAwait(false); 
+            
+            trigger.Start(false);
         }
 
         /// <summary>
@@ -404,10 +329,9 @@ namespace MediaBrowser.Common.ScheduledTasks
                 status = TaskCompletionStatus.Failed;
             }
 
+            var startTime = CurrentExecutionStartTime;
             var endTime = DateTime.UtcNow;
 
-            LogResult(endTime, status);
-
             Kernel.TcpManager.SendWebSocketMessage("ScheduledTaskEndExecute", LastExecutionResult);
 
             progress.ProgressChanged -= progress_ProgressChanged;
@@ -415,33 +339,7 @@ namespace MediaBrowser.Common.ScheduledTasks
             CurrentCancellationTokenSource = null;
             CurrentProgress = null;
 
-            TaskManager.OnTaskCompleted(this);
-        }
-
-        /// <summary>
-        /// Logs the result.
-        /// </summary>
-        /// <param name="endTime">The end time.</param>
-        /// <param name="status">The status.</param>
-        private void LogResult(DateTime endTime, TaskCompletionStatus status)
-        {
-            var startTime = CurrentExecutionStartTime;
-            var elapsedTime = endTime - startTime;
-            
-            Logger.Info("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
-
-            var result = new TaskResult
-            {
-                StartTimeUtc = startTime,
-                EndTimeUtc = endTime,
-                Status = status,
-                Name = Name,
-                Id = Id
-            };
-
-            JsonSerializer.SerializeToFile(result, HistoryFilePath);
-
-            LastExecutionResult = result;
+            TaskManager.OnTaskCompleted(this, startTime, endTime, status);
         }
 
         /// <summary>
@@ -501,7 +399,7 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 if (State == TaskState.Running)
                 {
-                    LogResult(DateTime.UtcNow, TaskCompletionStatus.Aborted);
+                    TaskManager.OnTaskCompleted(this, CurrentExecutionStartTime, DateTime.UtcNow, TaskCompletionStatus.Aborted);
                 }
 
                 if (CurrentCancellationTokenSource != null)
@@ -519,7 +417,7 @@ namespace MediaBrowser.Common.ScheduledTasks
             foreach (var trigger in Triggers)
             {
                 trigger.Triggered -= trigger_Triggered;
-                trigger.Dispose();
+                trigger.Stop();
             }
         }
     }

+ 0 - 64
MediaBrowser.Common/ScheduledTasks/BaseTaskTrigger.cs

@@ -1,64 +0,0 @@
-using System;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.ScheduledTasks
-{
-    /// <summary>
-    /// Use to indicate that a scheduled task should run
-    /// </summary>
-    public abstract class BaseTaskTrigger : IDisposable
-    {
-        /// <summary>
-        /// Fires when the trigger condition is satisfied and the task should run
-        /// </summary>
-        internal event EventHandler<EventArgs> Triggered;
-
-        /// <summary>
-        /// Called when [triggered].
-        /// </summary>
-        protected async void OnTriggered()
-        {
-            Stop();
-            
-            if (Triggered != null)
-            {
-                Triggered(this, EventArgs.Empty);
-            }
-
-            await Task.Delay(1000).ConfigureAwait(false);
-
-            Start(false);
-        }
-
-        /// <summary>
-        /// Stars waiting for the trigger action
-        /// </summary>
-        protected internal abstract void Start(bool isApplicationStartup);
-
-        /// <summary>
-        /// Stops waiting for the trigger action
-        /// </summary>
-        protected internal abstract void Stop();
-
-        /// <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)
-        {
-            if (dispose)
-            {
-                Stop();
-            }
-        }
-    }
-}

+ 16 - 14
MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Common.ScheduledTasks
     /// <summary>
     /// Represents a task trigger that fires everyday
     /// </summary>
-    public class DailyTrigger : BaseTaskTrigger
+    public class DailyTrigger : ITaskTrigger
     {
         /// <summary>
         /// Get the time of day to trigger the task to run
@@ -24,7 +24,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Stars waiting for the trigger action
         /// </summary>
         /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
-        protected internal override void Start(bool isApplicationStartup)
+        public void Start(bool isApplicationStartup)
         {
             DisposeTimer();
 
@@ -39,33 +39,35 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Stops waiting for the trigger action
         /// </summary>
-        protected internal override void Stop()
+        public void Stop()
         {
             DisposeTimer();
         }
 
         /// <summary>
-        /// Disposes this instance.
+        /// Disposes the timer.
         /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected override void Dispose(bool dispose)
+        private void DisposeTimer()
         {
-            if (dispose)
+            if (Timer != null)
             {
-                DisposeTimer();
+                Timer.Dispose();
             }
-
-            base.Dispose(dispose);
         }
 
         /// <summary>
-        /// Disposes the timer.
+        /// Occurs when [triggered].
         /// </summary>
-        private void DisposeTimer()
+        public event EventHandler<EventArgs> Triggered;
+
+        /// <summary>
+        /// Called when [triggered].
+        /// </summary>
+        private void OnTriggered()
         {
-            if (Timer != null)
+            if (Triggered != null)
             {
-                Timer.Dispose();
+                Triggered(this, EventArgs.Empty);
             }
         }
     }

+ 7 - 1
MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs

@@ -14,7 +14,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Gets the triggers.
         /// </summary>
         /// <value>The triggers.</value>
-        IEnumerable<BaseTaskTrigger> Triggers { get; set; }
+        IEnumerable<ITaskTrigger> Triggers { get; set; }
 
         /// <summary>
         /// Gets the last execution result.
@@ -75,5 +75,11 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Cancels if running.
         /// </summary>
         void CancelIfRunning();
+
+        /// <summary>
+        /// Gets the default triggers.
+        /// </summary>
+        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+        IEnumerable<ITaskTrigger> GetDefaultTriggers();
     }
 }

+ 27 - 2
MediaBrowser.Common/ScheduledTasks/ITaskManager.cs

@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Model.Tasks;
+using System;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Common.ScheduledTasks
@@ -41,6 +42,30 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Called when [task completed].
         /// </summary>
         /// <param name="task">The task.</param>
-        void OnTaskCompleted(IScheduledTask task);
+        /// <param name="startTime">The start time.</param>
+        /// <param name="endTime">The end time.</param>
+        /// <param name="status">The status.</param>
+        void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status);
+
+        /// <summary>
+        /// Gets the last execution result.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <returns>TaskResult.</returns>
+        TaskResult GetLastExecutionResult(IScheduledTask task);
+
+        /// <summary>
+        /// Loads the triggers.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+        IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task);
+
+        /// <summary>
+        /// Saves the triggers.
+        /// </summary>
+        /// <param name="task">The task.</param>
+        /// <param name="triggers">The triggers.</param>
+        void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers);
     }
 }

+ 26 - 0
MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs

@@ -0,0 +1,26 @@
+using System;
+
+namespace MediaBrowser.Common.ScheduledTasks
+{
+    /// <summary>
+    /// Interface ITaskTrigger
+    /// </summary>
+    public interface ITaskTrigger
+    {
+        /// <summary>
+        /// Fires when the trigger condition is satisfied and the task should run
+        /// </summary>
+        event EventHandler<EventArgs> Triggered;
+
+        /// <summary>
+        /// Stars waiting for the trigger action
+        /// </summary>
+        /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
+        void Start(bool isApplicationStartup);
+
+        /// <summary>
+        /// Stops waiting for the trigger action
+        /// </summary>
+        void Stop();
+    }
+}

+ 16 - 14
MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Common.ScheduledTasks
     /// <summary>
     /// Represents a task trigger that runs repeatedly on an interval
     /// </summary>
-    public class IntervalTrigger : BaseTaskTrigger
+    public class IntervalTrigger : ITaskTrigger
     {
         /// <summary>
         /// Gets or sets the interval.
@@ -24,7 +24,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Stars waiting for the trigger action
         /// </summary>
         /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
-        protected internal override void Start(bool isApplicationStartup)
+        public void Start(bool isApplicationStartup)
         {
             DisposeTimer();
 
@@ -34,33 +34,35 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Stops waiting for the trigger action
         /// </summary>
-        protected internal override void Stop()
+        public void Stop()
         {
             DisposeTimer();
         }
 
         /// <summary>
-        /// Disposes this instance.
+        /// Disposes the timer.
         /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected override void Dispose(bool dispose)
+        private void DisposeTimer()
         {
-            if (dispose)
+            if (Timer != null)
             {
-                DisposeTimer();
+                Timer.Dispose();
             }
-
-            base.Dispose(dispose);
         }
 
         /// <summary>
-        /// Disposes the timer.
+        /// Occurs when [triggered].
         /// </summary>
-        private void DisposeTimer()
+        public event EventHandler<EventArgs> Triggered;
+
+        /// <summary>
+        /// Called when [triggered].
+        /// </summary>
+        private void OnTriggered()
         {
-            if (Timer != null)
+            if (Triggered != null)
             {
-                Timer.Dispose();
+                Triggered(this, EventArgs.Empty);
             }
         }
     }

+ 2 - 2
MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs

@@ -35,7 +35,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// </summary>
         /// <param name="trigger">The trigger.</param>
         /// <returns>TaskTriggerInfo.</returns>
-        public static TaskTriggerInfo GetTriggerInfo(BaseTaskTrigger trigger)
+        public static TaskTriggerInfo GetTriggerInfo(ITaskTrigger trigger)
         {
             var info = new TaskTriggerInfo
             {
@@ -81,7 +81,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <returns>BaseTaskTrigger.</returns>
         /// <exception cref="System.ArgumentNullException"></exception>
         /// <exception cref="System.ArgumentException">Invalid trigger type:  + info.Type</exception>
-        public static BaseTaskTrigger GetTrigger(TaskTriggerInfo info)
+        public static ITaskTrigger GetTrigger(TaskTriggerInfo info)
         {
             if (info.Type.Equals(typeof(DailyTrigger).Name, StringComparison.OrdinalIgnoreCase))
             {

+ 21 - 4
MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs

@@ -1,17 +1,18 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
     /// <summary>
     /// Class StartupTaskTrigger
     /// </summary>
-    public class StartupTrigger : BaseTaskTrigger
+    public class StartupTrigger : ITaskTrigger
     {
         /// <summary>
         /// Stars waiting for the trigger action
         /// </summary>
         /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
-        protected internal async override void Start(bool isApplicationStartup)
+        public async void Start(bool isApplicationStartup)
         {
             if (isApplicationStartup)
             {
@@ -24,8 +25,24 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Stops waiting for the trigger action
         /// </summary>
-        protected internal override void Stop()
+        public void Stop()
         {
         }
+
+        /// <summary>
+        /// Occurs when [triggered].
+        /// </summary>
+        public event EventHandler<EventArgs> Triggered;
+
+        /// <summary>
+        /// Called when [triggered].
+        /// </summary>
+        private void OnTriggered()
+        {
+            if (Triggered != null)
+            {
+                Triggered(this, EventArgs.Empty);
+            }
+        }
     }
 }

+ 20 - 3
MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Model.Tasks;
 using Microsoft.Win32;
+using System;
 using System.Threading.Tasks;
 
 namespace MediaBrowser.Common.ScheduledTasks
@@ -7,7 +8,7 @@ namespace MediaBrowser.Common.ScheduledTasks
     /// <summary>
     /// Class SystemEventTrigger
     /// </summary>
-    public class SystemEventTrigger : BaseTaskTrigger
+    public class SystemEventTrigger : ITaskTrigger
     {
         /// <summary>
         /// Gets or sets the system event.
@@ -19,7 +20,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Stars waiting for the trigger action
         /// </summary>
         /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
-        protected internal override void Start(bool isApplicationStartup)
+        public void Start(bool isApplicationStartup)
         {
             switch (SystemEvent)
             {
@@ -32,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Stops waiting for the trigger action
         /// </summary>
-        protected internal override void Stop()
+        public void Stop()
         {
             SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
         }
@@ -52,5 +53,21 @@ namespace MediaBrowser.Common.ScheduledTasks
                 OnTriggered();
             }
         }
+
+        /// <summary>
+        /// Occurs when [triggered].
+        /// </summary>
+        public event EventHandler<EventArgs> Triggered;
+
+        /// <summary>
+        /// Called when [triggered].
+        /// </summary>
+        private void OnTriggered()
+        {
+            if (Triggered != null)
+            {
+                Triggered(this, EventArgs.Empty);
+            }
+        }
     }
 }

+ 0 - 159
MediaBrowser.Common/ScheduledTasks/TaskManager.cs

@@ -1,159 +0,0 @@
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Tasks;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MediaBrowser.Common.ScheduledTasks
-{
-    /// <summary>
-    /// Class TaskManager
-    /// </summary>
-    internal class TaskManager : ITaskManager
-    {
-        /// <summary>
-        /// Gets the list of Scheduled Tasks
-        /// </summary>
-        /// <value>The scheduled tasks.</value>
-        public IScheduledTask[] ScheduledTasks { get; private set; }
-
-        /// <summary>
-        /// The _task queue
-        /// </summary>
-        private readonly List<Type> _taskQueue = new List<Type>();
-
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="TaskManager" /> class.
-        /// </summary>
-        /// <param name="logger">The logger.</param>
-        public TaskManager(ILogger logger)
-        {
-            if (logger == null)
-            {
-                throw new ArgumentException("logger");
-            }
-
-            _logger = logger;
-
-            ScheduledTasks = new IScheduledTask[] {};
-        }
-
-        /// <summary>
-        /// Cancels if running and queue.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        public void CancelIfRunningAndQueue<T>()
-                 where T : IScheduledTask
-        {
-            ScheduledTasks.OfType<T>().First().CancelIfRunning();
-            QueueScheduledTask<T>();
-        }
-
-        /// <summary>
-        /// Queues the scheduled task.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        public void QueueScheduledTask<T>()
-            where T : IScheduledTask
-        {
-            var scheduledTask = ScheduledTasks.OfType<T>().First();
-
-            QueueScheduledTask(scheduledTask);
-        }
-
-        /// <summary>
-        /// Queues the scheduled task.
-        /// </summary>
-        /// <param name="task">The task.</param>
-        public void QueueScheduledTask(IScheduledTask task)
-        {
-            var type = task.GetType();
-
-            var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
-
-            lock (_taskQueue)
-            {
-                // If it's idle just execute immediately
-                if (scheduledTask.State == TaskState.Idle)
-                {
-                    scheduledTask.Execute();
-                    return;
-                }
-
-                if (!_taskQueue.Contains(type))
-                {
-                    _logger.Info("Queueing task {0}", type.Name);
-                    _taskQueue.Add(type);
-                }
-                else
-                {
-                    _logger.Info("Task already queued: {0}", type.Name);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Called when [task completed].
-        /// </summary>
-        /// <param name="task">The task.</param>
-        public void OnTaskCompleted(IScheduledTask task)
-        {
-            // Execute queued tasks
-            lock (_taskQueue)
-            {
-                var copy = _taskQueue.ToList();
-
-                foreach (var type in copy)
-                {
-                    var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
-
-                    if (scheduledTask.State == TaskState.Idle)
-                    {
-                        scheduledTask.Execute();
-
-                        _taskQueue.Remove(type);
-                    }
-                }
-            }
-        }
-
-        /// <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)
-        {
-            foreach (var task in ScheduledTasks)
-            {
-                task.Dispose();
-            }
-        }
-
-        /// <summary>
-        /// Adds the tasks.
-        /// </summary>
-        /// <param name="tasks">The tasks.</param>
-        public void AddTasks(IEnumerable<IScheduledTask> tasks)
-        {
-            var myTasks = ScheduledTasks.ToList();
-
-            myTasks.AddRange(tasks);
-
-            ScheduledTasks = myTasks.ToArray();
-        }
-    }
-}

+ 16 - 14
MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Common.ScheduledTasks
     /// <summary>
     /// Represents a task trigger that fires on a weekly basis
     /// </summary>
-    public class WeeklyTrigger : BaseTaskTrigger
+    public class WeeklyTrigger : ITaskTrigger
     {
         /// <summary>
         /// Get the time of day to trigger the task to run
@@ -30,7 +30,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Stars waiting for the trigger action
         /// </summary>
         /// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
-        protected internal override void Start(bool isApplicationStartup)
+        public void Start(bool isApplicationStartup)
         {
             DisposeTimer();
 
@@ -69,33 +69,35 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Stops waiting for the trigger action
         /// </summary>
-        protected internal override void Stop()
+        public void Stop()
         {
             DisposeTimer();
         }
 
         /// <summary>
-        /// Disposes this instance.
+        /// Disposes the timer.
         /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected override void Dispose(bool dispose)
+        private void DisposeTimer()
         {
-            if (dispose)
+            if (Timer != null)
             {
-                DisposeTimer();
+                Timer.Dispose();
             }
-
-            base.Dispose(dispose);
         }
 
         /// <summary>
-        /// Disposes the timer.
+        /// Occurs when [triggered].
         /// </summary>
-        private void DisposeTimer()
+        public event EventHandler<EventArgs> Triggered;
+
+        /// <summary>
+        /// Called when [triggered].
+        /// </summary>
+        private void OnTriggered()
         {
-            if (Timer != null)
+            if (Triggered != null)
             {
-                Timer.Dispose();
+                Triggered(this, EventArgs.Empty);
             }
         }
     }

+ 0 - 1
MediaBrowser.Common/packages.config

@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" />
   <package id="ServiceStack" version="3.9.37" targetFramework="net45" />
   <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" />
   <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" />

+ 30 - 15
MediaBrowser.Controller/Drawing/ImageManager.cs

@@ -1,12 +1,12 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Drawing
     /// <summary>
     /// Class ImageManager
     /// </summary>
-    public class ImageManager : BaseManager<Kernel>
+    public class ImageManager : IDisposable
     {
         /// <summary>
         /// Gets the image size cache.
@@ -57,20 +57,32 @@ namespace MediaBrowser.Controller.Drawing
         /// </summary>
         private readonly ILogger _logger;
 
+        /// <summary>
+        /// The _protobuf serializer
+        /// </summary>
+        private readonly IProtobufSerializer _protobufSerializer;
+
+        /// <summary>
+        /// The _kernel
+        /// </summary>
+        private readonly Kernel _kernel;
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageManager" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
-        public ImageManager(Kernel kernel, ILogger logger)
-            : base(kernel)
+        public ImageManager(Kernel kernel, IProtobufSerializer protobufSerializer, ILogger logger)
         {
+            _protobufSerializer = protobufSerializer;
             _logger = logger;
+            _kernel = kernel;
 
-            ImageSizeCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "image-sizes"));
-            ResizedImageCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "resized-images"));
-            CroppedImageCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "cropped-images"));
-            EnhancedImageCache = new FileSystemRepository(Path.Combine(Kernel.ApplicationPaths.ImageCachePath, "enhanced-images"));
+            ImageSizeCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "image-sizes"));
+            ResizedImageCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "resized-images"));
+            CroppedImageCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "cropped-images"));
+            EnhancedImageCache = new FileSystemRepository(Path.Combine(_kernel.ApplicationPaths.ImageCachePath, "enhanced-images"));
         }
 
         /// <summary>
@@ -276,7 +288,7 @@ namespace MediaBrowser.Controller.Drawing
 
             try
             {
-                var result = Kernel.ProtobufSerializer.DeserializeFromFile<int[]>(fullCachePath);
+                var result = _protobufSerializer.DeserializeFromFile<int[]>(fullCachePath);
 
                 return new ImageSize { Width = result[0], Height = result[1] };
             }
@@ -305,7 +317,7 @@ namespace MediaBrowser.Controller.Drawing
         {
             var output = new[] { width, height };
 
-            Kernel.ProtobufSerializer.SerializeToFile(output, cachePath);
+            _protobufSerializer.SerializeToFile(output, cachePath);
         }
 
         /// <summary>
@@ -472,7 +484,7 @@ namespace MediaBrowser.Controller.Drawing
                 throw new ArgumentNullException("item");
             }
 
-            var supportedEnhancers = Kernel.ImageEnhancers.Where(i => i.Supports(item, imageType)).ToList();
+            var supportedEnhancers = _kernel.ImageEnhancers.Where(i => i.Supports(item, imageType)).ToList();
 
             // No enhancement - don't cache
             if (supportedEnhancers.Count == 0)
@@ -526,7 +538,7 @@ namespace MediaBrowser.Controller.Drawing
             
             var dateModified = GetImageDateModified(item, imagePath);
 
-            var supportedEnhancers = Kernel.ImageEnhancers.Where(i => i.Supports(item, imageType));
+            var supportedEnhancers = _kernel.ImageEnhancers.Where(i => i.Supports(item, imageType));
 
             return GetImageCacheTag(imagePath, dateModified, supportedEnhancers, item, imageType);
         }
@@ -600,11 +612,16 @@ namespace MediaBrowser.Controller.Drawing
             return result;
         }
 
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
         /// <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 override void Dispose(bool dispose)
+        protected void Dispose(bool dispose)
         {
             if (dispose)
             {
@@ -613,8 +630,6 @@ namespace MediaBrowser.Controller.Drawing
                 CroppedImageCache.Dispose();
                 EnhancedImageCache.Dispose();
             }
-
-            base.Dispose(dispose);
         }
     }
 }

+ 7 - 8
MediaBrowser.Controller/Entities/User.cs

@@ -1,15 +1,13 @@
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Tasks;
 using System;
 using System.IO;
 using System.Linq;
 using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -170,7 +168,7 @@ namespace MediaBrowser.Controller.Entities
             get
             {
                 // Lazy load
-                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration<UserConfiguration>(ConfigurationFilePath, Logger));
+                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => (UserConfiguration)Kernel.Instance.GetXmlConfiguration(typeof(UserConfiguration), ConfigurationFilePath));
                 return _configuration;
             }
             private set
@@ -338,9 +336,9 @@ namespace MediaBrowser.Controller.Entities
         /// <summary>
         /// Saves the current configuration to the file system
         /// </summary>
-        public void SaveConfiguration()
+        public void SaveConfiguration(IXmlSerializer serializer)
         {
-            XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath);
+            serializer.SerializeToFile(Configuration, ConfigurationFilePath);
         }
 
         /// <summary>
@@ -376,8 +374,9 @@ namespace MediaBrowser.Controller.Entities
         /// Updates the configuration.
         /// </summary>
         /// <param name="config">The config.</param>
+        /// <param name="serializer">The serializer.</param>
         /// <exception cref="System.ArgumentNullException">config</exception>
-        public void UpdateConfiguration(UserConfiguration config)
+        public void UpdateConfiguration(UserConfiguration config, IXmlSerializer serializer)
         {
             if (config == null)
             {
@@ -387,7 +386,7 @@ namespace MediaBrowser.Controller.Entities
             var customLibraryChanged = config.UseCustomLibrary != Configuration.UseCustomLibrary;
 
             Configuration = config;
-            SaveConfiguration();
+            SaveConfiguration(serializer);
 
             // Force these to be lazy loaded again
             if (customLibraryChanged)

+ 85 - 0
MediaBrowser.Controller/IServerApplicationPaths.cs

@@ -0,0 +1,85 @@
+using MediaBrowser.Common.Kernel;
+
+namespace MediaBrowser.Controller
+{
+    public interface IServerApplicationPaths : IApplicationPaths
+    {
+        /// <summary>
+        /// Gets the path to the base root media directory
+        /// </summary>
+        /// <value>The root folder path.</value>
+        string RootFolderPath { get; }
+
+        /// <summary>
+        /// Gets the path to the default user view directory.  Used if no specific user view is defined.
+        /// </summary>
+        /// <value>The default user views path.</value>
+        string DefaultUserViewsPath { get; }
+
+        /// <summary>
+        /// Gets the path to localization data.
+        /// </summary>
+        /// <value>The localization path.</value>
+        string LocalizationPath { get; }
+
+        /// <summary>
+        /// Gets the path to the Images By Name directory
+        /// </summary>
+        /// <value>The images by name path.</value>
+        string ImagesByNamePath { get; }
+
+        /// <summary>
+        /// Gets the path to the People directory
+        /// </summary>
+        /// <value>The people path.</value>
+        string PeoplePath { get; }
+
+        /// <summary>
+        /// Gets the path to the Genre directory
+        /// </summary>
+        /// <value>The genre path.</value>
+        string GenrePath { get; }
+
+        /// <summary>
+        /// Gets the path to the Studio directory
+        /// </summary>
+        /// <value>The studio path.</value>
+        string StudioPath { get; }
+
+        /// <summary>
+        /// Gets the path to the Year directory
+        /// </summary>
+        /// <value>The year path.</value>
+        string YearPath { get; }
+
+        /// <summary>
+        /// Gets the path to the General IBN directory
+        /// </summary>
+        /// <value>The general path.</value>
+        string GeneralPath { get; }
+
+        /// <summary>
+        /// Gets the path to the Ratings IBN directory
+        /// </summary>
+        /// <value>The ratings path.</value>
+        string RatingsPath { get; }
+
+        /// <summary>
+        /// Gets the path to the user configuration directory
+        /// </summary>
+        /// <value>The user configuration directory path.</value>
+        string UserConfigurationDirectoryPath { get; }
+
+        /// <summary>
+        /// Gets the FF MPEG stream cache path.
+        /// </summary>
+        /// <value>The FF MPEG stream cache path.</value>
+        string FFMpegStreamCachePath { get; }
+
+        /// <summary>
+        /// Gets the folder path to tools
+        /// </summary>
+        /// <value>The media tools path.</value>
+        string MediaToolsPath { get; }
+    }
+}

+ 31 - 33
MediaBrowser.Controller/Kernel.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Common.Plugins;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
@@ -16,6 +17,7 @@ using MediaBrowser.Controller.Updates;
 using MediaBrowser.Controller.Weather;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
 using System;
 using System.Collections.Generic;
@@ -28,7 +30,7 @@ namespace MediaBrowser.Controller
     /// <summary>
     /// Class Kernel
     /// </summary>
-    public class Kernel : BaseKernel<ServerConfiguration, ServerApplicationPaths>
+    public class Kernel : BaseKernel<ServerConfiguration, IServerApplicationPaths>
     {
         /// <summary>
         /// The MB admin URL
@@ -291,17 +293,24 @@ namespace MediaBrowser.Controller
             get { return 7359; }
         }
 
+        private readonly ITaskManager _taskManager;
+
         /// <summary>
         /// Creates a kernel based on a Data path, which is akin to our current programdata path
         /// </summary>
         /// <param name="appHost">The app host.</param>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="xmlSerializer">The XML serializer.</param>
+        /// <param name="taskManager">The task manager.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">isoManager</exception>
-        public Kernel(IApplicationHost appHost, ILogger logger)
-            : base(appHost, logger)
+        public Kernel(IApplicationHost appHost, IServerApplicationPaths appPaths, IXmlSerializer xmlSerializer, ITaskManager taskManager, ILogger logger)
+            : base(appHost, appPaths, xmlSerializer, logger)
         {
             Instance = this;
 
+            _taskManager = taskManager;
+
             // For now there's no real way to inject this properly
             BaseItem.Logger = logger;
             Ratings.Logger = logger;
@@ -310,21 +319,10 @@ namespace MediaBrowser.Controller
             BaseMetadataProvider.Logger = logger;
         }
 
-        /// <summary>
-        /// Composes the exported values.
-        /// </summary>
-        protected override void RegisterExportedValues()
-        {
-            ApplicationHost.RegisterSingleInstance(this);
-            
-            base.RegisterExportedValues();
-        }
-
         /// <summary>
         /// Composes the parts with ioc container.
         /// </summary>
-        /// <param name="allTypes">All types.</param>
-        protected override void FindParts(Type[] allTypes)
+        protected override void FindParts()
         {
             InstallationManager = (InstallationManager)ApplicationHost.CreateInstance(typeof(InstallationManager));
             FFMpegManager = (FFMpegManager)ApplicationHost.CreateInstance(typeof(FFMpegManager));
@@ -335,21 +333,21 @@ namespace MediaBrowser.Controller
             UserDataManager = (UserDataManager)ApplicationHost.CreateInstance(typeof(UserDataManager));
             PluginSecurityManager = (PluginSecurityManager)ApplicationHost.CreateInstance(typeof(PluginSecurityManager));
             
-            base.FindParts(allTypes);
-
-            EntityResolutionIgnoreRules = GetExports<IResolutionIgnoreRule>(allTypes);
-            UserDataRepositories = GetExports<IUserDataRepository>(allTypes);
-            UserRepositories = GetExports<IUserRepository>(allTypes);
-            DisplayPreferencesRepositories = GetExports<IDisplayPreferencesRepository>(allTypes);
-            ItemRepositories = GetExports<IItemRepository>(allTypes);
-            WeatherProviders = GetExports<IWeatherProvider>(allTypes);
-            IntroProviders = GetExports<IIntroProvider>(allTypes);
-            PluginConfigurationPages = GetExports<IPluginConfigurationPage>(allTypes);
-            ImageEnhancers = GetExports<IImageEnhancer>(allTypes).OrderBy(e => e.Priority).ToArray();
-            PluginFolderCreators = GetExports<IVirtualFolderCreator>(allTypes);
-            StringFiles = GetExports<LocalizedStringData>(allTypes);
-            EntityResolvers = GetExports<IBaseItemResolver>(allTypes).OrderBy(e => e.Priority).ToArray();
-            MetadataProviders = GetExports<BaseMetadataProvider>(allTypes).OrderBy(e => e.Priority).ToArray();
+            base.FindParts();
+
+            EntityResolutionIgnoreRules = ApplicationHost.GetExports<IResolutionIgnoreRule>();
+            UserDataRepositories = ApplicationHost.GetExports<IUserDataRepository>();
+            UserRepositories = ApplicationHost.GetExports<IUserRepository>();
+            DisplayPreferencesRepositories = ApplicationHost.GetExports<IDisplayPreferencesRepository>();
+            ItemRepositories = ApplicationHost.GetExports<IItemRepository>();
+            WeatherProviders = ApplicationHost.GetExports<IWeatherProvider>();
+            IntroProviders = ApplicationHost.GetExports<IIntroProvider>();
+            PluginConfigurationPages = ApplicationHost.GetExports<IPluginConfigurationPage>();
+            ImageEnhancers = ApplicationHost.GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray();
+            PluginFolderCreators = ApplicationHost.GetExports<IVirtualFolderCreator>();
+            StringFiles = ApplicationHost.GetExports<LocalizedStringData>();
+            EntityResolvers = ApplicationHost.GetExports<IBaseItemResolver>().OrderBy(e => e.Priority).ToArray();
+            MetadataProviders = ApplicationHost.GetExports<BaseMetadataProvider>().OrderBy(e => e.Priority).ToArray();
         }
 
         /// <summary>
@@ -471,7 +469,7 @@ namespace MediaBrowser.Controller
         {
             DisposeFileSystemManager();
 
-            FileSystemManager = new FileSystemManager(this, Logger, TaskManager);
+            FileSystemManager = new FileSystemManager(this, Logger, _taskManager);
             FileSystemManager.StartWatchers();
         }
 
@@ -570,11 +568,11 @@ namespace MediaBrowser.Controller
                 ProviderManager.ValidateCurrentlyRunningProviders();
 
                 // Any number of configuration settings could change the way the library is refreshed, so do that now
-                TaskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
+                _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
 
                 if (refreshPeopleAfterUpdate)
                 {
-                    TaskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
+                    _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
                 }
             });
         }

+ 1 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -110,6 +110,7 @@
     <Compile Include="IO\FileSystem.cs" />
     <Compile Include="IO\FileSystemManager.cs" />
     <Compile Include="IO\NativeMethods.cs" />
+    <Compile Include="IServerApplicationPaths.cs" />
     <Compile Include="Library\ChildrenChangedEventArgs.cs" />
     <Compile Include="Library\DtoBuilder.cs" />
     <Compile Include="Library\Profiler.cs" />
@@ -183,7 +184,6 @@
     <Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
     <Compile Include="ScheduledTasks\PluginUpdateTask.cs" />
     <Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
-    <Compile Include="ServerApplicationPaths.cs" />
     <Compile Include="Library\ItemResolveArgs.cs" />
     <Compile Include="IO\DirectoryWatchers.cs" />
     <Compile Include="IO\FileData.cs" />

+ 58 - 21
MediaBrowser.Controller/MediaInfo/FFMpegManager.cs

@@ -1,12 +1,10 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Serialization;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
@@ -23,7 +21,7 @@ namespace MediaBrowser.Controller.MediaInfo
     /// <summary>
     /// Class FFMpegManager
     /// </summary>
-    public class FFMpegManager : BaseManager<Kernel>
+    public class FFMpegManager : IDisposable
     {
         /// <summary>
         /// Gets or sets the video image cache.
@@ -47,30 +45,66 @@ namespace MediaBrowser.Controller.MediaInfo
         /// Gets or sets the zip client.
         /// </summary>
         /// <value>The zip client.</value>
-        private IZipClient ZipClient { get; set; }
+        private readonly IZipClient _zipClient;
 
+        /// <summary>
+        /// The _logger
+        /// </summary>
+        private readonly Kernel _kernel;
+        
         /// <summary>
         /// The _logger
         /// </summary>
         private readonly ILogger _logger;
 
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// The _protobuf serializer
+        /// </summary>
+        private readonly IProtobufSerializer _protobufSerializer;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="FFMpegManager" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
         /// <param name="zipClient">The zip client.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">zipClient</exception>
-        public FFMpegManager(Kernel kernel, IZipClient zipClient, ILogger logger)
-            : base(kernel)
+        public FFMpegManager(Kernel kernel, IZipClient zipClient, IJsonSerializer jsonSerializer, IProtobufSerializer protobufSerializer, ILogger logger)
         {
+            if (kernel == null)
+            {
+                throw new ArgumentNullException("kernel");
+            }
             if (zipClient == null)
             {
                 throw new ArgumentNullException("zipClient");
             }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+            if (protobufSerializer == null)
+            {
+                throw new ArgumentNullException("protobufSerializer");
+            }
+            if (logger == null)
+            {
+                throw new ArgumentNullException("logger");
+            }
 
+            _kernel = kernel;
+            _zipClient = zipClient;
+            _jsonSerializer = jsonSerializer;
+            _protobufSerializer = protobufSerializer;
             _logger = logger;
-            ZipClient = zipClient;
 
             // Not crazy about this but it's the only way to suppress ffmpeg crash dialog boxes
             SetErrorMode(ErrorModes.SEM_FAILCRITICALERRORS | ErrorModes.SEM_NOALIGNMENTFAULTEXCEPT | ErrorModes.SEM_NOGPFAULTERRORBOX | ErrorModes.SEM_NOOPENFILEERRORBOX);
@@ -82,11 +116,16 @@ namespace MediaBrowser.Controller.MediaInfo
             Task.Run(() => VersionedDirectoryPath = GetVersionedDirectoryPath());
         }
 
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
         /// <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 override void Dispose(bool dispose)
+        protected void Dispose(bool dispose)
         {
             if (dispose)
             {
@@ -95,8 +134,6 @@ namespace MediaBrowser.Controller.MediaInfo
                 AudioImageCache.Dispose();
                 VideoImageCache.Dispose();
             }
-
-            base.Dispose(dispose);
         }
 
         /// <summary>
@@ -186,7 +223,7 @@ namespace MediaBrowser.Controller.MediaInfo
             {
                 if (_videoImagesDataPath == null)
                 {
-                    _videoImagesDataPath = Path.Combine(Kernel.ApplicationPaths.DataPath, "ffmpeg-video-images");
+                    _videoImagesDataPath = Path.Combine(_kernel.ApplicationPaths.DataPath, "ffmpeg-video-images");
 
                     if (!Directory.Exists(_videoImagesDataPath))
                     {
@@ -212,7 +249,7 @@ namespace MediaBrowser.Controller.MediaInfo
             {
                 if (_audioImagesDataPath == null)
                 {
-                    _audioImagesDataPath = Path.Combine(Kernel.ApplicationPaths.DataPath, "ffmpeg-audio-images");
+                    _audioImagesDataPath = Path.Combine(_kernel.ApplicationPaths.DataPath, "ffmpeg-audio-images");
 
                     if (!Directory.Exists(_audioImagesDataPath))
                     {
@@ -238,7 +275,7 @@ namespace MediaBrowser.Controller.MediaInfo
             {
                 if (_subtitleCachePath == null)
                 {
-                    _subtitleCachePath = Path.Combine(Kernel.ApplicationPaths.CachePath, "ffmpeg-subtitles");
+                    _subtitleCachePath = Path.Combine(_kernel.ApplicationPaths.CachePath, "ffmpeg-subtitles");
 
                     if (!Directory.Exists(_subtitleCachePath))
                     {
@@ -265,7 +302,7 @@ namespace MediaBrowser.Controller.MediaInfo
 
             var filename = resource.Substring(resource.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) + prefix.Length);
 
-            var versionedDirectoryPath = Path.Combine(Kernel.ApplicationPaths.MediaToolsPath, Path.GetFileNameWithoutExtension(filename));
+            var versionedDirectoryPath = Path.Combine(_kernel.ApplicationPaths.MediaToolsPath, Path.GetFileNameWithoutExtension(filename));
 
             if (!Directory.Exists(versionedDirectoryPath))
             {
@@ -287,7 +324,7 @@ namespace MediaBrowser.Controller.MediaInfo
         {
             using (var resourceStream = assembly.GetManifestResourceStream(zipFileResourcePath))
             {
-                ZipClient.ExtractAll(resourceStream, targetPath, false);
+                _zipClient.ExtractAll(resourceStream, targetPath, false);
             }
         }
 
@@ -353,7 +390,7 @@ namespace MediaBrowser.Controller.MediaInfo
             // Avoid File.Exists by just trying to deserialize
             try
             {
-                return Task.FromResult(Kernel.ProtobufSerializer.DeserializeFromFile<FFProbeResult>(cacheFilePath));
+                return Task.FromResult(_protobufSerializer.DeserializeFromFile<FFProbeResult>(cacheFilePath));
             }
             catch (FileNotFoundException)
             {
@@ -428,7 +465,7 @@ namespace MediaBrowser.Controller.MediaInfo
                     process.BeginErrorReadLine();
                 }
 
-                result = JsonSerializer.DeserializeFromStream<FFProbeResult>(process.StandardOutput.BaseStream);
+                result = _jsonSerializer.DeserializeFromStream<FFProbeResult>(process.StandardOutput.BaseStream);
 
                 if (extractChapters)
                 {
@@ -470,7 +507,7 @@ namespace MediaBrowser.Controller.MediaInfo
                 AddChapters(result, standardError);
             }
 
-            Kernel.ProtobufSerializer.SerializeToFile(result, cacheFile);
+            _protobufSerializer.SerializeToFile(result, cacheFile);
 
             return result;
         }
@@ -595,7 +632,7 @@ namespace MediaBrowser.Controller.MediaInfo
 
             if (saveItem && changesMade)
             {
-                await Kernel.ItemRepository.SaveItem(video, CancellationToken.None).ConfigureAwait(false);
+                await _kernel.ItemRepository.SaveItem(video, CancellationToken.None).ConfigureAwait(false);
             }
         }
 

+ 23 - 7
MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.MediaInfo;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -28,29 +29,44 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
         /// Gets or sets the bluray examiner.
         /// </summary>
         /// <value>The bluray examiner.</value>
-        private IBlurayExaminer BlurayExaminer { get; set; }
+        private readonly IBlurayExaminer _blurayExaminer;
 
-                /// <summary>
+        /// <summary>
         /// The _iso manager
         /// </summary>
         private readonly IIsoManager _isoManager;
 
+        /// <summary>
+        /// The _protobuf serializer
+        /// </summary>
+        private readonly IProtobufSerializer _protobufSerializer;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="FFProbeVideoInfoProvider" /> class.
         /// </summary>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="blurayExaminer">The bluray examiner.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <exception cref="System.ArgumentNullException">blurayExaminer</exception>
-        public FFProbeVideoInfoProvider(IIsoManager isoManager, IBlurayExaminer blurayExaminer)
+        public FFProbeVideoInfoProvider(IIsoManager isoManager, IBlurayExaminer blurayExaminer, IProtobufSerializer protobufSerializer)
             : base()
         {
+            if (isoManager == null)
+            {
+                throw new ArgumentNullException("isoManager");
+            }
             if (blurayExaminer == null)
             {
                 throw new ArgumentNullException("blurayExaminer");
             }
+            if (protobufSerializer == null)
+            {
+                throw new ArgumentNullException("protobufSerializer");
+            }
 
-            BlurayExaminer = blurayExaminer;
+            _blurayExaminer = blurayExaminer;
             _isoManager = isoManager;
+            _protobufSerializer = protobufSerializer;
 
             BdInfoCache = new FileSystemRepository(Path.Combine(Kernel.Instance.ApplicationPaths.CachePath, "bdinfo"));
         }
@@ -315,13 +331,13 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
 
             try
             {
-                result = Kernel.Instance.ProtobufSerializer.DeserializeFromFile<BlurayDiscInfo>(cacheFile);
+                result = _protobufSerializer.DeserializeFromFile<BlurayDiscInfo>(cacheFile);
             }
             catch (FileNotFoundException)
             {
                 result = GetBDInfo(inputPath);
 
-                Kernel.Instance.ProtobufSerializer.SerializeToFile(result, cacheFile);
+                _protobufSerializer.SerializeToFile(result, cacheFile);
             }
 
             cancellationToken.ThrowIfCancellationRequested();
@@ -400,7 +416,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
         /// <returns>VideoStream.</returns>
         private BlurayDiscInfo GetBDInfo(string path)
         {
-            return BlurayExaminer.GetDiscInfo(path);
+            return _blurayExaminer.GetDiscInfo(path);
         }
 
         /// <summary>

+ 26 - 5
MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Model.Entities;
@@ -15,6 +14,7 @@ using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Controller.Providers.Movies
 {
@@ -30,6 +30,27 @@ namespace MediaBrowser.Controller.Providers.Movies
     /// </summary>
     public class MovieDbProvider : BaseMetadataProvider
     {
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        protected IJsonSerializer JsonSerializer { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MovieDbProvider" /> class.
+        /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
+        public MovieDbProvider(IJsonSerializer jsonSerializer)
+            : base()
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+            JsonSerializer = jsonSerializer;
+        }
+
         /// <summary>
         /// Gets the priority.
         /// </summary>
@@ -93,7 +114,7 @@ namespace MediaBrowser.Controller.Providers.Movies
         {
             get
             {
-                LazyInitializer.EnsureInitialized(ref _tmdbSettingsTask, ref _tmdbSettingsTaskInitialized, ref _tmdbSettingsTaskSyncLock, GetTmdbSettings);
+                LazyInitializer.EnsureInitialized(ref _tmdbSettingsTask, ref _tmdbSettingsTaskInitialized, ref _tmdbSettingsTaskSyncLock, () => GetTmdbSettings(JsonSerializer));
                 return _tmdbSettingsTask;
             }
         }
@@ -102,13 +123,13 @@ namespace MediaBrowser.Controller.Providers.Movies
         /// Gets the TMDB settings.
         /// </summary>
         /// <returns>Task{TmdbSettingsResult}.</returns>
-        private static async Task<TmdbSettingsResult> GetTmdbSettings()
+        private static async Task<TmdbSettingsResult> GetTmdbSettings(IJsonSerializer jsonSerializer)
         {
             try
             {
                 using (var json = await Kernel.Instance.HttpManager.Get(String.Format(TmdbConfigUrl, ApiKey), Kernel.Instance.ResourcePools.MovieDb, CancellationToken.None).ConfigureAwait(false))
                 {
-                    return JsonSerializer.DeserializeFromStream<TmdbSettingsResult>(json);
+                    return jsonSerializer.DeserializeFromStream<TmdbSettingsResult>(json);
                 }
             }
             catch (HttpException e)
@@ -168,7 +189,7 @@ namespace MediaBrowser.Controller.Providers.Movies
             {
                 //in addition to ours, we need to set the last refreshed time for the local data provider
                 //so it won't see the new files we download and process them all over again
-                if (JsonProvider == null) JsonProvider = new MovieProviderFromJson();
+                if (JsonProvider == null) JsonProvider = new MovieProviderFromJson(JsonSerializer);
                 var data = item.ProviderData.GetValueOrDefault(JsonProvider.Id, new BaseProviderInfo { ProviderId = JsonProvider.Id });
                 data.LastRefreshed = value;
                 item.ProviderData[JsonProvider.Id] = data;

+ 6 - 2
MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs

@@ -1,5 +1,5 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.IO;
 using System.Threading;
@@ -12,6 +12,10 @@ namespace MediaBrowser.Controller.Providers.Movies
     /// </summary>
     public class MovieProviderFromJson : MovieDbProvider
     {
+        public MovieProviderFromJson(IJsonSerializer jsonSerializer) : base(jsonSerializer)
+        {
+        }
+
         /// <summary>
         /// Gets the priority.
         /// </summary>

+ 6 - 2
MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs

@@ -1,5 +1,5 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.IO;
 using System.Threading;
@@ -12,6 +12,10 @@ namespace MediaBrowser.Controller.Providers.Movies
     /// </summary>
     class PersonProviderFromJson : TmdbPersonProvider
     {
+        public PersonProviderFromJson(IJsonSerializer jsonSerializer) : base(jsonSerializer)
+        {
+        }
+
         /// <summary>
         /// Supportses the specified item.
         /// </summary>

+ 25 - 4
MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Net;
 using System;
@@ -10,6 +9,7 @@ using System.Linq;
 using System.Net;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Controller.Providers.Movies
 {
@@ -23,6 +23,27 @@ namespace MediaBrowser.Controller.Providers.Movies
         /// </summary>
         protected const string MetaFileName = "MBPerson.json";
 
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        protected IJsonSerializer JsonSerializer { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MovieDbProvider" /> class.
+        /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
+        public TmdbPersonProvider(IJsonSerializer jsonSerializer)
+            : base()
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+            JsonSerializer = jsonSerializer;
+        }
+
         /// <summary>
         /// Supportses the specified item.
         /// </summary>
@@ -56,7 +77,7 @@ namespace MediaBrowser.Controller.Providers.Movies
         protected override async Task<bool> FetchAsyncInternal(BaseItem item, bool force, CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
-            
+
             var person = (Person)item;
             var tasks = new List<Task>();
 
@@ -169,7 +190,7 @@ namespace MediaBrowser.Controller.Providers.Movies
             }
 
             cancellationToken.ThrowIfCancellationRequested();
-            
+
             if (searchResult != null && searchResult.Biography != null)
             {
                 ProcessInfo(person, searchResult);

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs

@@ -28,9 +28,9 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
-            return new BaseTaskTrigger[]
+            return new ITaskTrigger[]
                 {
                     new DailyTrigger { TimeOfDay = TimeSpan.FromHours(4) }
                 };

+ 4 - 3
MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs

@@ -20,7 +20,8 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Initializes a new instance of the <see cref="ImageCleanupTask" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
-        /// <param name="logger"></param>
+        /// <param name="taskManager">The task manager.</param>
+        /// <param name="logger">The logger.</param>
         public ImageCleanupTask(Kernel kernel, ITaskManager taskManager, ILogger logger)
             : base(kernel, taskManager, logger)
         {
@@ -30,9 +31,9 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
-            return new BaseTaskTrigger[]
+            return new ITaskTrigger[]
                 {
                     new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }
                 };

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs

@@ -26,9 +26,9 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
-            return new BaseTaskTrigger[]
+            return new ITaskTrigger[]
                 {
                     new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) },
 

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs

@@ -29,9 +29,9 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Creates the triggers that define when the task will run
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
-            return new BaseTaskTrigger[] { 
+            return new ITaskTrigger[] { 
             
                 // 1:30am
                 new DailyTrigger { TimeOfDay = TimeSpan.FromHours(1.5) },

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs

@@ -27,9 +27,9 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// Gets the default triggers.
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        protected override IEnumerable<BaseTaskTrigger> GetDefaultTriggers()
+        public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
         {
-            return new BaseTaskTrigger[] { 
+            return new ITaskTrigger[] { 
 
                 new StartupTrigger(),
 

+ 29 - 17
MediaBrowser.Controller/Updates/InstallationManager.cs

@@ -1,18 +1,17 @@
-using System.Security.Cryptography;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Progress;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Updates;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Security.Cryptography;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -32,8 +31,8 @@ namespace MediaBrowser.Controller.Updates
         /// <summary>
         /// The completed installations
         /// </summary>
-        public readonly ConcurrentBag<InstallationInfo> CompletedInstallations = new ConcurrentBag<InstallationInfo>(); 
-        
+        public readonly ConcurrentBag<InstallationInfo> CompletedInstallations = new ConcurrentBag<InstallationInfo>();
+
         #region PluginUninstalled Event
         /// <summary>
         /// Occurs when [plugin uninstalled].
@@ -68,7 +67,7 @@ namespace MediaBrowser.Controller.Updates
             _logger.Info("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.version, newVersion.classification);
 
             EventHelper.QueueEventIfNotNull(PluginUpdated, this, new GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> { Argument = new Tuple<IPlugin, PackageVersionInfo>(plugin, newVersion) }, _logger);
-            
+
             Kernel.NotifyPendingRestart();
         }
         #endregion
@@ -108,15 +107,22 @@ namespace MediaBrowser.Controller.Updates
         /// </summary>
         private readonly INetworkManager _networkManager;
 
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        protected IJsonSerializer JsonSerializer { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="InstallationManager" /> class.
         /// </summary>
         /// <param name="kernel">The kernel.</param>
         /// <param name="zipClient">The zip client.</param>
         /// <param name="networkManager">The network manager.</param>
+        /// <param name="jsonSerializer"></param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">zipClient</exception>
-        public InstallationManager(Kernel kernel, IZipClient zipClient, INetworkManager networkManager, ILogger logger)
+        public InstallationManager(Kernel kernel, IZipClient zipClient, INetworkManager networkManager, IJsonSerializer jsonSerializer, ILogger logger)
             : base(kernel)
         {
             if (zipClient == null)
@@ -131,6 +137,12 @@ namespace MediaBrowser.Controller.Updates
             {
                 throw new ArgumentNullException("logger");
             }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            JsonSerializer = jsonSerializer;
 
             _networkManager = networkManager;
             _logger = logger;
@@ -161,7 +173,7 @@ namespace MediaBrowser.Controller.Updates
                     package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
                         .OrderByDescending(v => v.version).ToList();
                 }
-                
+
                 if (packageType.HasValue)
                 {
                     packages = packages.Where(p => p.type == packageType.Value).ToList();
@@ -178,7 +190,7 @@ namespace MediaBrowser.Controller.Updates
 
                 // Remove packages with no versions
                 packages = packages.Where(p => p.versions.Any()).ToList();
-                
+
                 return packages;
             }
         }
@@ -320,7 +332,7 @@ namespace MediaBrowser.Controller.Updates
             var innerCancellationTokenSource = new CancellationTokenSource();
 
             var tuple = new Tuple<InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource);
-            
+
             // Add it to the in-progress list
             lock (CurrentInstallations)
             {
@@ -364,7 +376,7 @@ namespace MediaBrowser.Controller.Updates
                 _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr);
 
                 Kernel.TcpManager.SendWebSocketMessage("PackageInstallationCancelled", installationInfo);
-                
+
                 throw;
             }
             catch
@@ -373,7 +385,7 @@ namespace MediaBrowser.Controller.Updates
                 {
                     CurrentInstallations.Remove(tuple);
                 }
-                
+
                 Kernel.TcpManager.SendWebSocketMessage("PackageInstallationFailed", installationInfo);
 
                 throw;
@@ -421,7 +433,7 @@ namespace MediaBrowser.Controller.Updates
             }
 
             cancellationToken.ThrowIfCancellationRequested();
-            
+
             // Success - move it to the real target based on type
             if (isArchive)
             {
@@ -435,7 +447,7 @@ namespace MediaBrowser.Controller.Updates
                     throw;
                 }
 
-            } 
+            }
             else
             {
                 try
@@ -448,8 +460,8 @@ namespace MediaBrowser.Controller.Updates
                     _logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target);
                     throw;
                 }
-            }            
-            
+            }
+
             // Set last update time if we were installed before
             var plugin = Kernel.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
 

+ 3 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -75,6 +75,9 @@
     <Compile Include="Net\HttpException.cs" />
     <Compile Include="Net\NetworkShare.cs" />
     <Compile Include="Net\NetworkShareType.cs" />
+    <Compile Include="Serialization\IJsonSerializer.cs" />
+    <Compile Include="Serialization\IProtobufSerializer.cs" />
+    <Compile Include="Serialization\IXmlSerializer.cs" />
     <Compile Include="Updates\CheckForUpdateResult.cs" />
     <Compile Include="Updates\InstallationInfo.cs" />
     <Compile Include="Updates\PackageType.cs" />

+ 103 - 0
MediaBrowser.Model/Serialization/IJsonSerializer.cs

@@ -0,0 +1,103 @@
+using System;
+using System.IO;
+
+namespace MediaBrowser.Model.Serialization
+{
+    public interface IJsonSerializer
+    {
+        /// <summary>
+        /// Serializes to stream.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        /// <param name="stream">The stream.</param>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        void SerializeToStream<T>(T obj, Stream stream)
+            where T : class;
+
+        /// <summary>
+        /// Serializes to file.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        /// <param name="file">The file.</param>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        void SerializeToFile<T>(T obj, string file)
+            where T : class;
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="file">The file.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.ArgumentNullException">type</exception>
+        object DeserializeFromFile(Type type, string file);
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="file">The file.</param>
+        /// <returns>``0.</returns>
+        /// <exception cref="System.ArgumentNullException">file</exception>
+        T DeserializeFromFile<T>(string file)
+            where T : class;
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="stream">The stream.</param>
+        /// <returns>``0.</returns>
+        /// <exception cref="System.ArgumentNullException">stream</exception>
+        T DeserializeFromStream<T>(Stream stream);
+
+        /// <summary>
+        /// Deserializes from string.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="text">The text.</param>
+        /// <returns>``0.</returns>
+        /// <exception cref="System.ArgumentNullException">text</exception>
+        T DeserializeFromString<T>(string text);
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.ArgumentNullException">stream</exception>
+        object DeserializeFromStream(Stream stream, Type type);
+
+        /// <summary>
+        /// Deserializes from string.
+        /// </summary>
+        /// <param name="json">The json.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.ArgumentNullException">json</exception>
+        object DeserializeFromString(string json, Type type);
+
+        /// <summary>
+        /// Serializes to string.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.String.</returns>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        string SerializeToString<T>(T obj)
+            where T : class;
+
+        /// <summary>
+        /// Serializes to bytes.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.Byte[][].</returns>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        byte[] SerializeToBytes<T>(T obj)
+            where T : class;
+    }
+}

+ 63 - 0
MediaBrowser.Model/Serialization/IProtobufSerializer.cs

@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace MediaBrowser.Model.Serialization
+{
+    public interface IProtobufSerializer
+    {
+        /// <summary>
+        /// Serializes to stream.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <param name="stream">The stream.</param>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        void SerializeToStream(object obj, Stream stream);
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        /// <exception cref="System.ArgumentNullException">stream</exception>
+        object DeserializeFromStream(Stream stream, Type type);
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="stream">The stream.</param>
+        /// <returns>``0.</returns>
+        T DeserializeFromStream<T>(Stream stream)
+            where T : class;
+
+        /// <summary>
+        /// Serializes to file.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        /// <param name="file">The file.</param>
+        /// <exception cref="System.ArgumentNullException">file</exception>
+        void SerializeToFile<T>(T obj, string file);
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="file">The file.</param>
+        /// <returns>``0.</returns>
+        /// <exception cref="System.ArgumentNullException">file</exception>
+        T DeserializeFromFile<T>(string file)
+            where T : class;
+
+        /// <summary>
+        /// Serializes to bytes.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.Byte[][].</returns>
+        /// <exception cref="System.ArgumentNullException">obj</exception>
+        byte[] SerializeToBytes<T>(T obj)
+            where T : class;
+    }
+}

+ 69 - 0
MediaBrowser.Model/Serialization/IXmlSerializer.cs

@@ -0,0 +1,69 @@
+using System;
+using System.IO;
+
+namespace MediaBrowser.Model.Serialization
+{
+    public interface IXmlSerializer
+    {
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="stream">The stream.</param>
+        /// <returns>``0.</returns>
+        T DeserializeFromStream<T>(Stream stream);
+
+        /// <summary>
+        /// Deserializes from stream.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="stream">The stream.</param>
+        /// <returns>System.Object.</returns>
+        object DeserializeFromStream(Type type, Stream stream);
+
+        /// <summary>
+        /// Serializes to stream.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <param name="stream">The stream.</param>
+        void SerializeToStream(object obj, Stream stream);
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="file">The file.</param>
+        /// <returns>``0.</returns>
+        T DeserializeFromFile<T>(string file);
+
+        /// <summary>
+        /// Serializes to file.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <param name="file">The file.</param>
+        void SerializeToFile(object obj, string file);
+
+        /// <summary>
+        /// Deserializes from file.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="file">The file.</param>
+        /// <returns>System.Object.</returns>
+        object DeserializeFromFile(Type type, string file);
+
+        /// <summary>
+        /// Deserializes from bytes.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="buffer">The buffer.</param>
+        /// <returns>System.Object.</returns>
+        object DeserializeFromBytes(Type type, byte[] buffer);
+
+        /// <summary>
+        /// Serializes to bytes.
+        /// </summary>
+        /// <param name="obj">The obj.</param>
+        /// <returns>System.Byte[][].</returns>
+        byte[] SerializeToBytes(object obj);
+    }
+}

+ 2 - 0
MediaBrowser.Networking/MediaBrowser.Networking.csproj

@@ -112,6 +112,8 @@
     <Compile Include="Management\NetworkManager.cs" />
     <Compile Include="Management\NetworkShares.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Web\ServerFactory.cs" />
+    <Compile Include="Web\NativeWebSocket.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">

+ 19 - 2
MediaBrowser.Networking/Web/HttpServer.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using ServiceStack.Api.Swagger;
 using ServiceStack.Common.Web;
 using ServiceStack.Configuration;
@@ -60,6 +61,12 @@ namespace MediaBrowser.Networking.Web
         /// <value>The HTTP listener.</value>
         private IDisposable HttpListener { get; set; }
 
+        /// <summary>
+        /// Gets or sets the protobuf serializer.
+        /// </summary>
+        /// <value>The protobuf serializer.</value>
+        private IProtobufSerializer ProtobufSerializer { get; set; }
+        
         /// <summary>
         /// Occurs when [web socket connected].
         /// </summary>
@@ -82,17 +89,22 @@ namespace MediaBrowser.Networking.Web
         /// </summary>
         /// <param name="applicationHost">The application host.</param>
         /// <param name="kernel">The kernel.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="serverName">Name of the server.</param>
         /// <param name="defaultRedirectpath">The default redirectpath.</param>
         /// <exception cref="System.ArgumentNullException">urlPrefix</exception>
-        public HttpServer(IApplicationHost applicationHost, IKernel kernel, ILogger logger, string serverName, string defaultRedirectpath)
+        public HttpServer(IApplicationHost applicationHost, IKernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath)
             : base()
         {
             if (kernel == null)
             {
                 throw new ArgumentNullException("kernel");
             }
+            if (protobufSerializer == null)
+            {
+                throw new ArgumentNullException("protobufSerializer");
+            }
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
@@ -112,6 +124,7 @@ namespace MediaBrowser.Networking.Web
 
             ServerName = serverName;
             DefaultRedirectPath = defaultRedirectpath;
+            ProtobufSerializer = protobufSerializer;
             _logger = logger;
             ApplicationHost = applicationHost;
 
@@ -121,7 +134,7 @@ namespace MediaBrowser.Networking.Web
             Kernel = kernel;
 
             EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager());
-            ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => Kernel.ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => Kernel.ProtobufSerializer.DeserializeFromStream(stream, type));
+            ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => ProtobufSerializer.DeserializeFromStream(stream, type));
 
             Init();
         }
@@ -132,6 +145,10 @@ namespace MediaBrowser.Networking.Web
         /// <param name="container">The container.</param>
         public override void Configure(Container container)
         {
+            JsConfig.DateHandler = JsonDateHandler.ISO8601;
+            JsConfig.ExcludeTypeInfo = true;
+            JsConfig.IncludeNullValues = false;
+            
             SetConfig(new EndpointHostConfig
             {
                 DefaultRedirectPath = DefaultRedirectPath,

+ 3 - 17
MediaBrowser.Common/Net/NativeWebSocket.cs → MediaBrowser.Networking/Web/NativeWebSocket.cs

@@ -1,7 +1,5 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Logging;
 using System;
-using System.IO;
 using System.Net.WebSockets;
 using System.Threading;
 using System.Threading.Tasks;
@@ -79,19 +77,7 @@ namespace MediaBrowser.Common.Net
 
                 if (OnReceiveDelegate != null)
                 {
-                    using (var memoryStream = new MemoryStream(bytes))
-                    {
-                        try
-                        {
-                            var messageResult = JsonSerializer.DeserializeFromStream<WebSocketMessageInfo>(memoryStream);
-
-                            OnReceiveDelegate(messageResult);
-                        }
-                        catch (Exception ex)
-                        {
-                            _logger.ErrorException("Error processing web socket message", ex);
-                        }
-                    }
+                    OnReceiveDelegate(bytes);
                 }
             }
         }
@@ -154,6 +140,6 @@ namespace MediaBrowser.Common.Net
         /// Gets or sets the receive action.
         /// </summary>
         /// <value>The receive action.</value>
-        public Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; }
+        public Action<byte[]> OnReceiveDelegate { get; set; }
     }
 }

+ 28 - 0
MediaBrowser.Networking/Web/ServerFactory.cs

@@ -0,0 +1,28 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+
+namespace MediaBrowser.Networking.Web
+{
+    /// <summary>
+    /// Class ServerFactory
+    /// </summary>
+    public static class ServerFactory
+    {
+        /// <summary>
+        /// Creates the server.
+        /// </summary>
+        /// <param name="applicationHost">The application host.</param>
+        /// <param name="kernel">The kernel.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
+        /// <param name="logger">The logger.</param>
+        /// <param name="serverName">Name of the server.</param>
+        /// <param name="defaultRedirectpath">The default redirectpath.</param>
+        /// <returns>IHttpServer.</returns>
+        public static IHttpServer CreateServer(IApplicationHost applicationHost, IKernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath)
+        {
+            return new HttpServer(applicationHost, kernel, protobufSerializer, logger, serverName, defaultRedirectpath);
+        }
+    }
+}

+ 4 - 4
MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs

@@ -1,9 +1,9 @@
 using Alchemy.Classes;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Serialization;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Net.WebSockets;
+using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -83,9 +83,9 @@ namespace MediaBrowser.Networking.WebSocket
                 {
                     try
                     {
-                        var messageResult = JsonSerializer.DeserializeFromString<WebSocketMessageInfo>(json);
+                        var bytes = Encoding.UTF8.GetBytes(json);
 
-                        OnReceiveDelegate(messageResult);
+                        OnReceiveDelegate(bytes);
                     }
                     catch (Exception ex)
                     {
@@ -128,6 +128,6 @@ namespace MediaBrowser.Networking.WebSocket
         /// Gets or sets the receive action.
         /// </summary>
         /// <value>The receive action.</value>
-        public Action<WebSocketMessageInfo> OnReceiveDelegate { get; set; }
+        public Action<byte[]> OnReceiveDelegate { get; set; }
     }
 }

+ 30 - 26
MediaBrowser.Server.Sqlite/MediaBrowser.Server.Sqlite.csproj → MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -4,11 +4,11 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}</ProjectGuid>
+    <ProjectGuid>{2E781478-814D-4A48-9D80-BFF206441A65}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>MediaBrowser.Server.Sqlite</RootNamespace>
-    <AssemblyName>MediaBrowser.Server.Sqlite</AssemblyName>
+    <RootNamespace>MediaBrowser.Server.Implementations</RootNamespace>
+    <AssemblyName>MediaBrowser.Server.Implementations</AssemblyName>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
@@ -31,9 +31,6 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
-  <PropertyGroup>
-    <RunPostBuildEvent>Always</RunPostBuildEvent>
-  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
@@ -43,33 +40,31 @@
     <Reference Include="System.Data.SQLite.Linq">
       <HintPath>..\packages\System.Data.SQLite.1.0.84.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
     </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\SharedVersion.cs">
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="SQLiteDisplayPreferencesRepository.cs" />
-    <Compile Include="SQLiteExtensions.cs" />
-    <Compile Include="SQLiteItemRepository.cs" />
-    <Compile Include="SQLiteRepository.cs" />
-    <Compile Include="SQLiteUserDataRepository.cs" />
-    <Compile Include="SQLiteUserRepository.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="x64\SQLite.Interop.dll">
-      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
-    </Content>
-    <Content Include="x86\SQLite.Interop.dll">
-      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
-    </Content>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
+    <Compile Include="ServerApplicationPaths.cs" />
+    <Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
+    <Compile Include="Sqlite\SQLiteExtensions.cs" />
+    <Compile Include="Sqlite\SQLiteItemRepository.cs" />
+    <Compile Include="Sqlite\SQLiteRepository.cs" />
+    <Compile Include="Sqlite\SQLiteUserDataRepository.cs" />
+    <Compile Include="Sqlite\SQLiteUserRepository.cs" />
+    <Compile Include="WorldWeatherOnline\WeatherProvider.cs" />
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj">
+      <Project>{c4d2573a-3fd3-441f-81af-174ac4cd4e1d}</Project>
+      <Name>MediaBrowser.Common.Implementations</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>
@@ -83,11 +78,20 @@
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="x64\SQLite.Interop.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="x86\SQLite.Interop.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
-  <PropertyGroup>
-    <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\MediaBrowser.ServerApplication\CorePlugins\" /y</PostBuildEvent>
-  </PropertyGroup>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 4 - 5
MediaBrowser.Server.WorldWeatherOnline/Properties/AssemblyInfo.cs → MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs

@@ -1,15 +1,14 @@
 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.Server.WorldWeatherOnline")]
+[assembly: AssemblyTitle("MediaBrowser.Server.Implementations")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MediaBrowser.Server.WorldWeatherOnline")]
+[assembly: AssemblyProduct("MediaBrowser.Server.Implementations")]
 [assembly: AssemblyCopyright("Copyright ©  2013")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
@@ -20,7 +19,7 @@ using System.Runtime.InteropServices;
 [assembly: ComVisible(false)]
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("c7b294dc-b3fd-4925-9ac3-8dd16803200c")]
+[assembly: Guid("0537cdd3-a069-4d86-9318-d46d8b119903")]
 
 // Version information for an assembly consists of the following four values:
 //
@@ -28,4 +27,4 @@ using System.Runtime.InteropServices;
 //      Minor Version 
 //      Build Number
 //      Revision
-//
+//

+ 4 - 3
MediaBrowser.Controller/ServerApplicationPaths.cs → MediaBrowser.Server.Implementations/ServerApplicationPaths.cs

@@ -1,12 +1,13 @@
-using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Implementations;
+using MediaBrowser.Controller;
 using System.IO;
 
-namespace MediaBrowser.Controller
+namespace MediaBrowser.Server.Implementations
 {
     /// <summary>
     /// Extends BaseApplicationPaths to add paths that are only applicable on the server
     /// </summary>
-    public class ServerApplicationPaths : BaseApplicationPaths
+    public class ServerApplicationPaths : BaseApplicationPaths, IServerApplicationPaths
     {
         /// <summary>
         /// The _root folder path

+ 31 - 6
MediaBrowser.Server.Sqlite/SQLiteDisplayPreferencesRepository.cs → MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs

@@ -1,8 +1,9 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Data;
@@ -10,7 +11,7 @@ using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.Sqlite
+namespace MediaBrowser.Server.Implementations.Sqlite
 {
     /// <summary>
     /// Class SQLiteDisplayPreferencesRepository
@@ -34,13 +35,37 @@ namespace MediaBrowser.Server.Sqlite
             }
         }
 
+        /// <summary>
+        /// The _protobuf serializer
+        /// </summary>
+        private readonly IProtobufSerializer _protobufSerializer;
+
+        /// <summary>
+        /// The _app paths
+        /// </summary>
+        private readonly IApplicationPaths _appPaths;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
         /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
-        public SQLiteDisplayPreferencesRepository(ILogger logger)
+        /// <exception cref="System.ArgumentNullException">protobufSerializer</exception>
+        public SQLiteDisplayPreferencesRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogger logger)
             : base(logger)
         {
+            if (protobufSerializer == null)
+            {
+                throw new ArgumentNullException("protobufSerializer");
+            }
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+
+            _protobufSerializer = protobufSerializer;
+            _appPaths = appPaths;
         }
 
         /// <summary>
@@ -49,7 +74,7 @@ namespace MediaBrowser.Server.Sqlite
         /// <returns>Task.</returns>
         public async Task Initialize()
         {
-            var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "displaypreferences.db");
+            var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
 
             await ConnectToDB(dbFile).ConfigureAwait(false);
 
@@ -104,7 +129,7 @@ namespace MediaBrowser.Server.Sqlite
                         cmd.AddParam("@1", item.DisplayPrefsId);
                         cmd.AddParam("@2", data.UserId);
 
-                        cmd.AddParam("@3", Kernel.Instance.ProtobufSerializer.SerializeToBytes(data));
+                        cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data));
 
                         QueueCommand(cmd);
                     }
@@ -136,7 +161,7 @@ namespace MediaBrowser.Server.Sqlite
                 {
                     using (var stream = GetStream(reader, 0))
                     {
-                        var data = Kernel.Instance.ProtobufSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+                        var data = _protobufSerializer.DeserializeFromStream<DisplayPreferences>(stream);
                         if (data != null)
                         {
                             yield return data;

+ 1 - 1
MediaBrowser.Server.Sqlite/SQLiteExtensions.cs → MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs

@@ -2,7 +2,7 @@
 using System.Data;
 using System.Data.SQLite;
 
-namespace MediaBrowser.Server.Sqlite
+namespace MediaBrowser.Server.Implementations.Sqlite
 {
     /// <summary>
     /// Class SQLiteExtensions

+ 33 - 8
MediaBrowser.Server.Sqlite/SQLiteItemRepository.cs → MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs

@@ -1,8 +1,8 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Data;
@@ -10,7 +10,7 @@ using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.Sqlite
+namespace MediaBrowser.Server.Implementations.Sqlite
 {
     /// <summary>
     /// Class SQLiteItemRepository
@@ -39,13 +39,38 @@ namespace MediaBrowser.Server.Sqlite
             }
         }
 
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// The _app paths
+        /// </summary>
+        private readonly IApplicationPaths _appPaths;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
         /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
-        public SQLiteItemRepository(ILogger logger)
+        /// <exception cref="System.ArgumentNullException">appPaths</exception>
+        public SQLiteItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogger logger)
             : base(logger)
         {
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _appPaths = appPaths;
+            _jsonSerializer = jsonSerializer;
         }
 
         /// <summary>
@@ -54,7 +79,7 @@ namespace MediaBrowser.Server.Sqlite
         /// <returns>Task.</returns>
         public async Task Initialize()
         {
-            var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "library.db");
+            var dbFile = Path.Combine(_appPaths.DataPath, "library.db");
 
             await ConnectToDB(dbFile).ConfigureAwait(false);
 
@@ -111,7 +136,7 @@ namespace MediaBrowser.Server.Sqlite
 
             return Task.Run(() =>
             {
-                var serialized = JsonSerializer.SerializeToBytes(item);
+                var serialized = _jsonSerializer.SerializeToBytes(item);
 
                 cancellationToken.ThrowIfCancellationRequested();
 
@@ -173,7 +198,7 @@ namespace MediaBrowser.Server.Sqlite
                             return null;
                         }
 
-                        var item = JsonSerializer.DeserializeFromStream(stream, itemType);
+                        var item = _jsonSerializer.DeserializeFromStream(stream, itemType);
                         return item as BaseItem;
                     }
                 }
@@ -213,7 +238,7 @@ namespace MediaBrowser.Server.Sqlite
                             Logger.Error("Cannot find type {0}.  Probably belongs to plug-in that is no longer loaded.", type);
                             continue;
                         }
-                        var item = JsonSerializer.DeserializeFromStream(stream, itemType) as BaseItem;
+                        var item = _jsonSerializer.DeserializeFromStream(stream, itemType) as BaseItem;
                         if (item != null)
                         {
                             item.Parent = parent;

+ 1 - 1
MediaBrowser.Server.Sqlite/SQLiteRepository.cs → MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs

@@ -8,7 +8,7 @@ using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.Sqlite
+namespace MediaBrowser.Server.Implementations.Sqlite
 {
     /// <summary>
     /// Class SqliteRepository

+ 31 - 6
MediaBrowser.Server.Sqlite/SQLiteUserDataRepository.cs → MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs

@@ -1,7 +1,8 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Data;
@@ -9,7 +10,7 @@ using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.Sqlite
+namespace MediaBrowser.Server.Implementations.Sqlite
 {
     /// <summary>
     /// Class SQLiteUserDataRepository
@@ -33,13 +34,37 @@ namespace MediaBrowser.Server.Sqlite
             }
         }
 
+        /// <summary>
+        /// The _protobuf serializer
+        /// </summary>
+        private readonly IProtobufSerializer _protobufSerializer;
+
+        /// <summary>
+        /// The _app paths
+        /// </summary>
+        private readonly IApplicationPaths _appPaths;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
         /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="protobufSerializer">The protobuf serializer.</param>
         /// <param name="logger">The logger.</param>
-        public SQLiteUserDataRepository(ILogger logger)
+        /// <exception cref="System.ArgumentNullException">protobufSerializer</exception>
+        public SQLiteUserDataRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogger logger)
             : base(logger)
         {
+            if (protobufSerializer == null)
+            {
+                throw new ArgumentNullException("protobufSerializer");
+            }
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+
+            _protobufSerializer = protobufSerializer;
+            _appPaths = appPaths;
         }
 
         /// <summary>
@@ -48,7 +73,7 @@ namespace MediaBrowser.Server.Sqlite
         /// <returns>Task.</returns>
         public async Task Initialize()
         {
-            var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "userdata.db");
+            var dbFile = Path.Combine(_appPaths.DataPath, "userdata.db");
 
             await ConnectToDB(dbFile).ConfigureAwait(false);
 
@@ -103,7 +128,7 @@ namespace MediaBrowser.Server.Sqlite
                         cmd.AddParam("@1", item.UserDataId);
                         cmd.AddParam("@2", data.UserId);
 
-                        cmd.AddParam("@3", Kernel.Instance.ProtobufSerializer.SerializeToBytes(data));
+                        cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data));
 
                         QueueCommand(cmd);
                     }
@@ -135,7 +160,7 @@ namespace MediaBrowser.Server.Sqlite
                 {
                     using (var stream = GetStream(reader, 0))
                     {
-                        var data = Kernel.Instance.ProtobufSerializer.DeserializeFromStream<UserItemData>(stream);
+                        var data = _protobufSerializer.DeserializeFromStream<UserItemData>(stream);
                         if (data != null)
                         {
                             yield return data;

+ 33 - 8
MediaBrowser.Server.Sqlite/SQLiteUserRepository.cs → MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs

@@ -1,16 +1,16 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Data;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
 
-namespace MediaBrowser.Server.Sqlite
+namespace MediaBrowser.Server.Implementations.Sqlite
 {
     /// <summary>
     /// Class SQLiteUserRepository
@@ -34,13 +34,38 @@ namespace MediaBrowser.Server.Sqlite
             }
         }
 
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        /// <summary>
+        /// The _app paths
+        /// </summary>
+        private readonly IApplicationPaths _appPaths;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
         /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
-        public SQLiteUserRepository(ILogger logger)
+        /// <exception cref="System.ArgumentNullException">appPaths</exception>
+        public SQLiteUserRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogger logger)
             : base(logger)
         {
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _appPaths = appPaths;
+            _jsonSerializer = jsonSerializer;
         }
 
         /// <summary>
@@ -49,7 +74,7 @@ namespace MediaBrowser.Server.Sqlite
         /// <returns>Task.</returns>
         public async Task Initialize()
         {
-            var dbFile = Path.Combine(Kernel.Instance.ApplicationPaths.DataPath, "users.db");
+            var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
 
             await ConnectToDB(dbFile).ConfigureAwait(false);
 
@@ -88,7 +113,7 @@ namespace MediaBrowser.Server.Sqlite
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
-                var serialized = JsonSerializer.SerializeToBytes(user);
+                var serialized = _jsonSerializer.SerializeToBytes(user);
 
                 cancellationToken.ThrowIfCancellationRequested();
 
@@ -115,7 +140,7 @@ namespace MediaBrowser.Server.Sqlite
                 {
                     using (var stream = GetStream(reader, 0))
                     {
-                        var user = JsonSerializer.DeserializeFromStream<User>(stream);
+                        var user = _jsonSerializer.DeserializeFromStream<User>(stream);
                         yield return user;
                     }
                 }

+ 17 - 4
MediaBrowser.Server.WorldWeatherOnline/WeatherProvider.cs → MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs

@@ -1,14 +1,14 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Weather;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Weather;
 using System;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.WorldWeatherOnline
+namespace MediaBrowser.Server.Implementations.WorldWeatherOnline
 {
     /// <summary>
     /// Based on http://www.worldweatheronline.com/free-weather-feed.aspx
@@ -22,18 +22,31 @@ namespace MediaBrowser.Server.WorldWeatherOnline
         /// <value>The logger.</value>
         private ILogger Logger { get; set; }
 
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        protected IJsonSerializer JsonSerializer { get; private set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="WeatherProvider" /> class.
         /// </summary>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">logger</exception>
-        public WeatherProvider(ILogger logger)
+        public WeatherProvider(IJsonSerializer jsonSerializer, ILogger logger)
         {
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
             }
 
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            JsonSerializer = jsonSerializer;
             Logger = logger;
         }
 

+ 0 - 0
MediaBrowser.Server.Sqlite/packages.config → MediaBrowser.Server.Implementations/packages.config


+ 11 - 183
MediaBrowser.ServerApplication/App.xaml.cs

@@ -1,26 +1,13 @@
-using BDInfo;
-using MediaBrowser.ClickOnce;
-using MediaBrowser.Common.IO;
+using MediaBrowser.ClickOnce;
+using MediaBrowser.Common.Implementations.Serialization;
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
-using MediaBrowser.IsoMounter;
 using MediaBrowser.Logging.Nlog;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Updates;
-using MediaBrowser.Networking.Management;
-using MediaBrowser.Networking.Udp;
-using MediaBrowser.Networking.Web;
-using MediaBrowser.Networking.WebSocket;
 using MediaBrowser.Server.Uninstall;
-using MediaBrowser.ServerApplication.Implementations;
 using Microsoft.Win32;
-using SimpleInjector;
 using System;
 using System.Diagnostics;
-using System.IO;
 using System.Linq;
 using System.Net.Cache;
 using System.Threading;
@@ -35,7 +22,7 @@ namespace MediaBrowser.ServerApplication
     /// <summary>
     /// Interaction logic for App.xaml
     /// </summary>
-    public partial class App : Application, IApplicationHost
+    public partial class App : Application
     {
         /// <summary>
         /// Defines the entry point of the application.
@@ -78,16 +65,11 @@ namespace MediaBrowser.ServerApplication
         protected ILogger Logger { get; set; }
 
         /// <summary>
-        /// Gets or sets the log file path.
+        /// Gets or sets the composition root.
         /// </summary>
-        /// <value>The log file path.</value>
-        public string LogFilePath { get; private set; }
-
-        /// <summary>
-        /// The container
-        /// </summary>
-        private Container _container = new Container();
-
+        /// <value>The composition root.</value>
+        protected ApplicationHost CompositionRoot { get; set; }
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="App" /> class.
         /// </summary>
@@ -135,12 +117,6 @@ namespace MediaBrowser.ServerApplication
             get { return "MediaBrowser.Server.Uninstall.exe"; }
         }
 
-        /// <summary>
-        /// Gets or sets the iso manager.
-        /// </summary>
-        /// <value>The iso manager.</value>
-        private IIsoManager IsoManager { get; set; }
-
         /// <summary>
         /// Gets or sets a value indicating whether [last run at startup value].
         /// </summary>
@@ -198,13 +174,13 @@ namespace MediaBrowser.ServerApplication
         /// </summary>
         protected async void LoadKernel()
         {
-            Kernel = new Kernel(this, Logger);
+            CompositionRoot = new ApplicationHost(Logger);
 
-            RegisterResources();
+            Kernel = CompositionRoot.Kernel;
 
             try
             {
-                new MainWindow(Logger).Show();
+                new MainWindow(new JsonSerializer(), Logger).Show();
 
                 var now = DateTime.UtcNow;
 
@@ -281,6 +257,7 @@ namespace MediaBrowser.ServerApplication
             base.OnExit(e);
 
             Kernel.Dispose();
+            CompositionRoot.Dispose();
         }
 
         /// <summary>
@@ -391,17 +368,6 @@ namespace MediaBrowser.ServerApplication
             Dispatcher.Invoke(Shutdown);
         }
 
-        /// <summary>
-        /// Reloads the logger.
-        /// </summary>
-        /// <exception cref="System.NotImplementedException"></exception>
-        public void ReloadLogger()
-        {
-            LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log");
-
-            NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging);
-        }
-
         /// <summary>
         /// Gets the image.
         /// </summary>
@@ -477,143 +443,5 @@ namespace MediaBrowser.ServerApplication
             RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant);
             return bitmap;
         }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance can self update.
-        /// </summary>
-        /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
-        public bool CanSelfUpdate
-        {
-            get { return ClickOnceHelper.IsNetworkDeployed; }
-        }
-
-        /// <summary>
-        /// Checks for update.
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task{CheckForUpdateResult}.</returns>
-        public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress);
-        }
-
-        /// <summary>
-        /// Updates the application.
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task.</returns>
-        public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            return new ApplicationUpdater().UpdateApplication(cancellationToken, progress);
-        }
-
-        /// <summary>
-        /// Registers resources that classes will depend on
-        /// </summary>
-        private void RegisterResources()
-        {
-            RegisterSingleInstance<IApplicationHost>(this);
-            RegisterSingleInstance(Logger);
-
-            IsoManager = new PismoIsoManager(Logger);
-
-            RegisterSingleInstance(IsoManager);
-            RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer());
-            RegisterSingleInstance<INetworkManager>(() => new NetworkManager());
-            RegisterSingleInstance<IZipClient>(() => new DotNetZipClient());
-            RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger));
-            Register(typeof(IUdpServer), typeof(UdpServer));
-            RegisterSingleInstance<IHttpServer>(() => new HttpServer(this, Kernel, Logger, "Media Browser", "index.html"));
-        }
-
-        /// <summary>
-        /// Creates an instance of type and resolves all constructor dependancies
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <returns>System.Object.</returns>
-        public object CreateInstance(Type type)
-        {
-            try
-            {
-                return _container.GetInstance(type);
-            }
-            catch
-            {
-                Logger.Error("Error creating {0}", type.Name);
-
-                throw;
-            }
-        }
-
-        /// <summary>
-        /// Registers the specified obj.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="obj">The obj.</param>
-        public void RegisterSingleInstance<T>(T obj)
-            where T : class
-        {
-            _container.RegisterSingle(obj);
-        }
-
-        /// <summary>
-        /// Registers the specified func.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="func">The func.</param>
-        public void Register<T>(Func<T> func)
-            where T : class
-        {
-            _container.Register(func);
-        }
-
-        /// <summary>
-        /// Registers the single instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="func">The func.</param>
-        public void RegisterSingleInstance<T>(Func<T> func)
-            where T : class
-        {
-            _container.RegisterSingle(func);
-        }
-
-        /// <summary>
-        /// Resolves this instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <returns>``0.</returns>
-        public T Resolve<T>()
-        {
-            return (T)_container.GetRegistration(typeof(T), true).GetInstance();
-        }
-
-        /// <summary>
-        /// Resolves this instance.
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <returns>``0.</returns>
-        public T TryResolve<T>()
-        {
-            var result = _container.GetRegistration(typeof(T), false);
-
-            if (result == null)
-            {
-                return default(T);
-            }
-            return (T)result.GetInstance();
-        }
-
-        /// <summary>
-        /// Registers the specified service type.
-        /// </summary>
-        /// <param name="serviceType">Type of the service.</param>
-        /// <param name="implementation">Type of the concrete.</param>
-        public void Register(Type serviceType, Type implementation)
-        {
-            _container.Register(serviceType, implementation);
-        }
     }
 }

+ 498 - 0
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -0,0 +1,498 @@
+using BDInfo;
+using MediaBrowser.ClickOnce;
+using MediaBrowser.Common.Implementations.ScheduledTasks;
+using MediaBrowser.Common.Implementations.Serialization;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller;
+using MediaBrowser.IsoMounter;
+using MediaBrowser.Logging.Nlog;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.System;
+using MediaBrowser.Model.Updates;
+using MediaBrowser.Networking.Management;
+using MediaBrowser.Networking.Udp;
+using MediaBrowser.Networking.Web;
+using MediaBrowser.Networking.WebSocket;
+using MediaBrowser.Server.Implementations;
+using MediaBrowser.ServerApplication.Implementations;
+using SimpleInjector;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.ServerApplication
+{
+    /// <summary>
+    /// Class CompositionRoot
+    /// </summary>
+    public class ApplicationHost : IApplicationHost, IDisposable
+    {
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
+
+        /// <summary>
+        /// Gets or sets the iso manager.
+        /// </summary>
+        /// <value>The iso manager.</value>
+        private IIsoManager IsoManager { get; set; }
+
+        /// <summary>
+        /// Gets or sets the log file path.
+        /// </summary>
+        /// <value>The log file path.</value>
+        public string LogFilePath { get; private set; }
+
+        /// <summary>
+        /// The container
+        /// </summary>
+        private readonly Container _container = new Container();
+
+        /// <summary>
+        /// Gets or sets the kernel.
+        /// </summary>
+        /// <value>The kernel.</value>
+        public Kernel Kernel { get; private set; }
+
+        private readonly List<string> _failedAssemblies = new List<string>();
+        /// <summary>
+        /// Gets assemblies that failed to load
+        /// </summary>
+        public IEnumerable<string> FailedAssemblies
+        {
+            get { return _failedAssemblies; }
+        }
+
+        /// <summary>
+        /// Gets all types within all running assemblies
+        /// </summary>
+        /// <value>All types.</value>
+        public Type[] AllTypes { get; private set; }
+
+        /// <summary>
+        /// Gets all concrete types.
+        /// </summary>
+        /// <value>All concrete types.</value>
+        public Type[] AllConcreteTypes { get; private set; }
+
+        /// <summary>
+        /// The disposable parts
+        /// </summary>
+        private readonly List<IDisposable> _disposableParts = new List<IDisposable>();
+
+        /// <summary>
+        /// The json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer = new JsonSerializer();
+
+        /// <summary>
+        /// The _XML serializer
+        /// </summary>
+        private readonly IXmlSerializer _xmlSerializer = new XmlSerializer();
+
+        /// <summary>
+        /// The _application paths
+        /// </summary>
+        private readonly IServerApplicationPaths _applicationPaths = new ServerApplicationPaths();
+
+        /// <summary>
+        /// The _task manager
+        /// </summary>
+        private readonly ITaskManager _taskManager;
+        
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
+        /// </summary>
+        /// <param name="logger">The logger.</param>
+        public ApplicationHost(ILogger logger)
+        {
+            Logger = logger;
+
+            _taskManager = new TaskManager(_applicationPaths, _jsonSerializer, Logger);
+
+            Kernel = new Kernel(this, _applicationPaths, _xmlSerializer, _taskManager, Logger);
+
+            RegisterResources();
+
+            FindParts();
+        }
+
+        /// <summary>
+        /// Registers resources that classes will depend on
+        /// </summary>
+        internal void RegisterResources()
+        {
+            DiscoverTypes();
+
+            RegisterSingleInstance<IKernel>(Kernel);
+            RegisterSingleInstance(Kernel);
+            
+            RegisterSingleInstance<IApplicationHost>(this);
+            RegisterSingleInstance(Logger);
+
+            IsoManager = new PismoIsoManager(Logger);
+
+            RegisterSingleInstance(_applicationPaths);
+            RegisterSingleInstance<IApplicationPaths>(_applicationPaths);
+
+            RegisterSingleInstance(IsoManager);
+            RegisterSingleInstance(_taskManager);
+            RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer());
+            RegisterSingleInstance<INetworkManager>(() => new NetworkManager());
+            RegisterSingleInstance<IZipClient>(() => new DotNetZipClient());
+            RegisterSingleInstance<IWebSocketServer>(() => new AlchemyServer(Logger));
+            RegisterSingleInstance(_jsonSerializer);
+            RegisterSingleInstance(_xmlSerializer);
+            RegisterSingleInstance<IProtobufSerializer>(() => ProtobufSerializer);
+            Register(typeof(IUdpServer), typeof(UdpServer));
+            RegisterSingleInstance(() => ServerFactory.CreateServer(this, Kernel, ProtobufSerializer, Logger, "Media Browser", "index.html"));
+        }
+
+        /// <summary>
+        /// Discovers the types.
+        /// </summary>
+        private void DiscoverTypes()
+        {
+            _failedAssemblies.Clear();
+
+            AllTypes = GetComposablePartAssemblies().SelectMany(GetTypes).ToArray();
+
+            AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
+        }
+
+        /// <summary>
+        /// Finds the parts.
+        /// </summary>
+        private void FindParts()
+        {
+            _taskManager.AddTasks(GetExports<IScheduledTask>(false));
+        }
+
+        /// <summary>
+        /// Gets a list of types within an assembly
+        /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
+        /// </summary>
+        /// <param name="assembly">The assembly.</param>
+        /// <returns>IEnumerable{Type}.</returns>
+        /// <exception cref="System.ArgumentNullException">assembly</exception>
+        private IEnumerable<Type> GetTypes(Assembly assembly)
+        {
+            if (assembly == null)
+            {
+                throw new ArgumentNullException("assembly");
+            }
+
+            try
+            {
+                return assembly.GetTypes();
+            }
+            catch (ReflectionTypeLoadException ex)
+            {
+                // If it fails we can still get a list of the Types it was able to resolve
+                return ex.Types.Where(t => t != null);
+            }
+        }
+
+        /// <summary>
+        /// The _protobuf serializer initialized
+        /// </summary>
+        private bool _protobufSerializerInitialized;
+        /// <summary>
+        /// The _protobuf serializer sync lock
+        /// </summary>
+        private object _protobufSerializerSyncLock = new object();
+        /// <summary>
+        /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection
+        /// </summary>
+        private ProtobufSerializer _protobufSerializer;
+        /// <summary>
+        /// Gets the protobuf serializer.
+        /// </summary>
+        /// <value>The protobuf serializer.</value>
+        public ProtobufSerializer ProtobufSerializer
+        {
+            get
+            {
+                // Lazy load
+                LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => ProtobufSerializer.Create(AllTypes));
+                return _protobufSerializer;
+            }
+            private set
+            {
+                _protobufSerializer = value;
+                _protobufSerializerInitialized = value != null;
+            }
+        }
+
+        /// <summary>
+        /// Creates an instance of type and resolves all constructor dependancies
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>System.Object.</returns>
+        public object CreateInstance(Type type)
+        {
+            try
+            {
+                return _container.GetInstance(type);
+            }
+            catch
+            {
+                Logger.Error("Error creating {0}", type.Name);
+
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Registers the specified obj.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj">The obj.</param>
+        public void RegisterSingleInstance<T>(T obj)
+            where T : class
+        {
+            _container.RegisterSingle(obj);
+        }
+
+        /// <summary>
+        /// Registers the specified func.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="func">The func.</param>
+        public void Register<T>(Func<T> func)
+            where T : class
+        {
+            _container.Register(func);
+        }
+
+        /// <summary>
+        /// Registers the single instance.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="func">The func.</param>
+        public void RegisterSingleInstance<T>(Func<T> func)
+            where T : class
+        {
+            _container.RegisterSingle(func);
+        }
+
+        /// <summary>
+        /// Resolves this instance.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns>``0.</returns>
+        public T Resolve<T>()
+        {
+            return (T)_container.GetRegistration(typeof(T), true).GetInstance();
+        }
+
+        /// <summary>
+        /// Resolves this instance.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns>``0.</returns>
+        public T TryResolve<T>()
+        {
+            var result = _container.GetRegistration(typeof(T), false);
+
+            if (result == null)
+            {
+                return default(T);
+            }
+            return (T)result.GetInstance();
+        }
+
+        /// <summary>
+        /// Registers the specified service type.
+        /// </summary>
+        /// <param name="serviceType">Type of the service.</param>
+        /// <param name="implementation">Type of the concrete.</param>
+        public void Register(Type serviceType, Type implementation)
+        {
+            _container.Register(serviceType, implementation);
+        }
+
+        /// <summary>
+        /// Restarts this instance.
+        /// </summary>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public void Restart()
+        {
+            App.Instance.Restart();
+        }
+
+        /// <summary>
+        /// Reloads the logger.
+        /// </summary>
+        /// <exception cref="System.NotImplementedException"></exception>
+        public void ReloadLogger()
+        {
+            LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log");
+
+            NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging);
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance can self update.
+        /// </summary>
+        /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
+        public bool CanSelfUpdate
+        {
+            get { return ClickOnceHelper.IsNetworkDeployed; }
+        }
+
+        /// <summary>
+        /// Checks for update.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task{CheckForUpdateResult}.</returns>
+        public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress);
+        }
+
+        /// <summary>
+        /// Updates the application.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task.</returns>
+        public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new ApplicationUpdater().UpdateApplication(cancellationToken, progress);
+        }
+
+        /// <summary>
+        /// Gets the composable part assemblies.
+        /// </summary>
+        /// <returns>IEnumerable{Assembly}.</returns>
+        private IEnumerable<Assembly> GetComposablePartAssemblies()
+        {
+            // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
+            // This will prevent the .dll file from getting locked, and allow us to replace it when needed
+            foreach (var pluginAssembly in Directory
+                .EnumerateFiles(Kernel.ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
+                .Select(LoadAssembly).Where(a => a != null))
+            {
+                yield return pluginAssembly;
+            }
+
+            var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
+            var corePluginDirectory = Path.Combine(runningDirectory, "CorePlugins");
+
+            // This will prevent the .dll file from getting locked, and allow us to replace it when needed
+            foreach (var pluginAssembly in Directory
+                .EnumerateFiles(corePluginDirectory, "*.dll", SearchOption.TopDirectoryOnly)
+                .Select(LoadAssembly).Where(a => a != null))
+            {
+                yield return pluginAssembly;
+            }
+
+            // Include composable parts in the Model assembly 
+            yield return typeof(SystemInfo).Assembly;
+
+            // Include composable parts in the Common assembly 
+            yield return typeof(IKernel).Assembly;
+
+            // Include composable parts in the Controller assembly 
+            yield return typeof(Kernel).Assembly;
+
+            // Common implementations
+            yield return typeof(TaskManager).Assembly;
+
+            // Server implementations
+            yield return typeof(ServerApplicationPaths).Assembly;
+            
+            // Include composable parts in the running assembly
+            yield return GetType().Assembly;
+        }
+
+        /// <summary>
+        /// Loads the assembly.
+        /// </summary>
+        /// <param name="file">The file.</param>
+        /// <returns>Assembly.</returns>
+        private Assembly LoadAssembly(string file)
+        {
+            try
+            {
+                return Assembly.Load(File.ReadAllBytes((file)));
+            }
+            catch (Exception ex)
+            {
+                _failedAssemblies.Add(file);
+                Logger.ErrorException("Error loading assembly {0}", ex, file);
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Gets the exports.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="allTypes">All types.</param>
+        /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
+        /// <returns>IEnumerable{``0}.</returns>
+        public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
+        {
+            var currentType = typeof(T);
+
+            Logger.Info("Composing instances of " + currentType.Name);
+
+            var parts = AllConcreteTypes.Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray();
+
+            if (manageLiftime)
+            {
+                _disposableParts.AddRange(parts.OfType<IDisposable>());
+            }
+
+            return parts;
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        /// <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)
+        {
+            IsoManager.Dispose();
+
+            foreach (var part in _disposableParts)
+            {
+                part.Dispose();
+            }
+
+            _disposableParts.Clear();
+        }
+    }
+
+    public class MyClass
+    {
+        public MyClass()
+        {
+            
+        }
+    }
+}

+ 9 - 6
MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs

@@ -1,11 +1,12 @@
-using MediaBrowser.Common.Serialization;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -18,7 +19,6 @@ using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Input;
 using System.Windows.Media.Imaging;
-using MediaBrowser.Model.Logging;
 
 namespace MediaBrowser.ServerApplication
 {
@@ -27,8 +27,10 @@ namespace MediaBrowser.ServerApplication
     /// </summary>
     public partial class LibraryExplorer : Window
     {
-        private ILogger _logger;
+        private readonly ILogger _logger;
 
+        private readonly IJsonSerializer _jsonSerializer;
+        
         /// <summary>
         /// The current user
         /// </summary>
@@ -36,9 +38,10 @@ namespace MediaBrowser.ServerApplication
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryExplorer" /> class.
         /// </summary>
-        public LibraryExplorer(ILogger logger)
+        public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger)
         {
             _logger = logger;
+            _jsonSerializer = jsonSerializer;
 
             InitializeComponent();
             lblVersion.Content = "Version: " + Kernel.Instance.ApplicationVersion;
@@ -161,7 +164,7 @@ namespace MediaBrowser.ServerApplication
                     lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Hidden;
 
                 }
-                txtData.Text = FormatJson(JsonSerializer.SerializeToString(item)) + trailers + features;
+                txtData.Text = FormatJson(_jsonSerializer.SerializeToString(item)) + trailers + features;
 
                 var previews = new List<PreviewItem>();
                 await Task.Run(() =>

+ 13 - 2
MediaBrowser.ServerApplication/MainWindow.xaml.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.ServerApplication.Controls;
 using MediaBrowser.ServerApplication.Logging;
 using System;
@@ -38,6 +39,11 @@ namespace MediaBrowser.ServerApplication
         /// <value>The new item timer.</value>
         private Timer NewItemTimer { get; set; }
 
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+        
         /// <summary>
         /// The _logger
         /// </summary>
@@ -48,13 +54,18 @@ namespace MediaBrowser.ServerApplication
         /// </summary>
         /// <param name="logger">The logger.</param>
         /// <exception cref="System.ArgumentNullException">logger</exception>
-        public MainWindow(ILogger logger)
+        public MainWindow(IJsonSerializer jsonSerializer, ILogger logger)
         {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
             if (logger == null)
             {
                 throw new ArgumentNullException("logger");
             }
 
+            _jsonSerializer = jsonSerializer;
             _logger = logger;
 
             InitializeComponent();
@@ -282,7 +293,7 @@ namespace MediaBrowser.ServerApplication
         /// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
         private void cmOpenExplorer_click(object sender, RoutedEventArgs e)
         {
-            (new LibraryExplorer(_logger)).Show();
+            (new LibraryExplorer(_jsonSerializer, _logger)).Show();
         }
 
         /// <summary>

+ 9 - 30
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -128,36 +128,6 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\ThirdParty\UPnP\Libs\Platinum.Managed.dll</HintPath>
     </Reference>
-    <Reference Include="ServiceStack, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Common, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Common.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Interfaces, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Common.3.9.37\lib\net35\ServiceStack.Interfaces.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.OrmLite, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.OrmLite.SqlServer">
-      <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.37\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Redis">
-      <HintPath>..\packages\ServiceStack.Redis.3.9.37\lib\net35\ServiceStack.Redis.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.3.9.37\lib\net35\ServiceStack.ServiceInterface.dll</HintPath>
-    </Reference>
-    <Reference Include="ServiceStack.Text, Version=3.9.37.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
-    </Reference>
     <Reference Include="SimpleInjector, Version=2.0.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\SimpleInjector.2.0.0-beta5\lib\net40-client\SimpleInjector.dll</HintPath>
@@ -220,6 +190,7 @@
       <DependentUpon>App.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="ApplicationHost.cs" />
     <Compile Include="Controls\ItemUpdateNotification.xaml.cs">
       <DependentUpon>ItemUpdateNotification.xaml</DependentUpon>
     </Compile>
@@ -279,6 +250,10 @@
       <Project>{cc96bf3e-0bda-4809-bc4b-bb6d418f4a84}</Project>
       <Name>MediaBrowser.ClickOnce</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj">
+      <Project>{c4d2573a-3fd3-441f-81af-174ac4cd4e1d}</Project>
+      <Name>MediaBrowser.Common.Implementations</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>
@@ -303,6 +278,10 @@
       <Project>{7c11010e-179a-49b7-bfb2-f1656f5e71ad}</Project>
       <Name>MediaBrowser.Networking</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
+      <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
+      <Name>MediaBrowser.Server.Implementations</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Server.Uninstall\MediaBrowser.Server.Uninstall.csproj">
       <Project>{5443422f-9548-417a-90dd-2fc91f2b5999}</Project>
       <Name>MediaBrowser.Server.Uninstall</Name>

+ 0 - 5
MediaBrowser.ServerApplication/packages.config

@@ -3,11 +3,6 @@
   <package id="DotNetZip" version="1.9.1.8" targetFramework="net45" />
   <package id="Hardcodet.Wpf.TaskbarNotification" version="1.0.4.0" targetFramework="net45" />
   <package id="NLog" version="2.0.0.2000" targetFramework="net45" />
-  <package id="ServiceStack" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.Common" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.OrmLite.SqlServer" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.Redis" version="3.9.37" targetFramework="net45" />
-  <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
   <package id="SimpleInjector" version="2.0.0-beta5" targetFramework="net45" />
   <package id="System.Data.SQLite" version="1.0.84.0" targetFramework="net45" />
 </packages>

+ 1 - 2
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -1,7 +1,6 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Common.ScheduledTasks.Tasks;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Plugins;
@@ -137,7 +136,7 @@ namespace MediaBrowser.WebDashboard.Api
                                      .Select(ScheduledTaskHelpers.GetTaskInfo)
                                      .ToArray(),
 
-                ApplicationUpdateTaskId = taskManager.ScheduledTasks.OfType<SystemUpdateTask>().First().Id,
+                ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id,
 
                 ActiveConnections = connections,
 

+ 32 - 49
MediaBrowser.sln

@@ -20,8 +20,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		Performance19.psess = Performance19.psess
 	EndProjectSection
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction.Javascript", "MediaBrowser.ApiInteraction.Javascript\MediaBrowser.ApiInteraction.Javascript.csproj", "{767B536E-D90C-4D74-A14B-8564B16F3499}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction", "MediaBrowser.ApiInteraction\MediaBrowser.ApiInteraction.csproj", "{921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction.Portable", "MediaBrowser.ApiInteraction.Portable\MediaBrowser.ApiInteraction.Portable.csproj", "{52E0C440-85C0-4A99-ACFE-07C87B2600BE}"
@@ -41,10 +39,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.IsoMounter", "
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Installer", "MediaBrowser.Installer\MediaBrowser.Installer.csproj", "{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Sqlite", "MediaBrowser.Server.Sqlite\MediaBrowser.Server.Sqlite.csproj", "{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.WorldWeatherOnline", "MediaBrowser.Server.WorldWeatherOnline\MediaBrowser.Server.WorldWeatherOnline.csproj", "{973CA45C-8362-490B-8327-C68098FD4891}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Logging.NLog", "MediaBrowser.Logging.NLog\MediaBrowser.Logging.NLog.csproj", "{67310740-0EC4-4DC2-9921-33DF38B20167}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ClickOnce", "MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj", "{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}"
@@ -53,6 +47,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Networking", "
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Uninstaller", "MediaBrowser.Uninstaller\MediaBrowser.Uninstaller.csproj", "{FACAF749-3E28-46DD-B613-654FCD434959}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common.Implementations", "MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj", "{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -163,21 +161,6 @@ Global
 		{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x64.ActiveCfg = Release|Any CPU
 		{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU
 		{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Win32.ActiveCfg = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|x86.Build.0 = Debug|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Any CPU.Build.0 = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Mixed Platforms.Build.0 = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|Win32.ActiveCfg = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|x64.ActiveCfg = Release|Any CPU
-		{767B536E-D90C-4D74-A14B-8564B16F3499}.Release|x86.ActiveCfg = Release|Any CPU
 		{921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -266,34 +249,6 @@ Global
 		{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Release|Win32.ActiveCfg = Release|Any CPU
 		{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Release|x64.ActiveCfg = Release|Any CPU
 		{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Release|x86.ActiveCfg = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|Win32.ActiveCfg = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|Win32.ActiveCfg = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|x64.ActiveCfg = Release|Any CPU
-		{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}.Release|x86.ActiveCfg = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|Win32.ActiveCfg = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|Any CPU.Build.0 = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|Mixed Platforms.Build.0 = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|Win32.ActiveCfg = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|x64.ActiveCfg = Release|Any CPU
-		{973CA45C-8362-490B-8327-C68098FD4891}.Release|x86.ActiveCfg = Release|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -350,6 +305,34 @@ Global
 		{FACAF749-3E28-46DD-B613-654FCD434959}.Release|Win32.ActiveCfg = Release|Any CPU
 		{FACAF749-3E28-46DD-B613-654FCD434959}.Release|x64.ActiveCfg = Release|Any CPU
 		{FACAF749-3E28-46DD-B613-654FCD434959}.Release|x86.ActiveCfg = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|Win32.ActiveCfg = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Win32.ActiveCfg = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x64.ActiveCfg = Release|Any CPU
+		{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Win32.ActiveCfg = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|Win32.ActiveCfg = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|x64.ActiveCfg = Release|Any CPU
+		{2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE