소스 검색

added IServerEntryPoint to replace plugin.initialize

LukePulverenti 12 년 전
부모
커밋
0ea90ef7c6
27개의 변경된 파일487개의 추가작업 그리고 534개의 파일을 삭제
  1. 1 0
      MediaBrowser.Api/MediaBrowser.Api.csproj
  2. 3 3
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  3. 2 2
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  4. 2 2
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  5. 1 1
      MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
  6. 13 290
      MediaBrowser.Api/Plugin.cs
  7. 15 7
      MediaBrowser.Api/PluginService.cs
  8. 333 0
      MediaBrowser.Api/ServerEntryPoint.cs
  9. 21 2
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  10. 3 77
      MediaBrowser.Common/Kernel/BaseKernel.cs
  11. 14 1
      MediaBrowser.Common/Kernel/IApplicationHost.cs
  12. 1 14
      MediaBrowser.Common/Kernel/IKernel.cs
  13. 16 80
      MediaBrowser.Common/Plugins/BasePlugin.cs
  14. 10 24
      MediaBrowser.Common/Plugins/IPlugin.cs
  15. 1 1
      MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
  16. 14 10
      MediaBrowser.Controller/Kernel.cs
  17. 1 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  18. 15 0
      MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
  19. 3 3
      MediaBrowser.Controller/Updates/InstallationManager.cs
  20. 0 5
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  21. 1 1
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  22. 1 1
      MediaBrowser.Server.Implementations/packages.config
  23. 1 1
      MediaBrowser.ServerApplication/App.xaml.cs
  24. 3 0
      MediaBrowser.sln
  25. 5 4
      Nuget/MediaBrowser.Common.Internal.nuspec
  26. 3 2
      Nuget/MediaBrowser.Common.nuspec
  27. 4 3
      Nuget/MediaBrowser.Server.Core.nuspec

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

@@ -97,6 +97,7 @@
     <Compile Include="PluginService.cs" />
     <Compile Include="ScheduledTasks\ScheduledTaskService.cs" />
     <Compile Include="ScheduledTasks\ScheduledTasksWebSocketListener.cs" />
+    <Compile Include="ServerEntryPoint.cs" />
     <Compile Include="SystemService.cs" />
     <Compile Include="UserLibrary\BaseItemsByNameService.cs" />
     <Compile Include="UserLibrary\GenresService.cs" />

+ 3 - 3
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -518,7 +518,7 @@ namespace MediaBrowser.Api.Playback
                 EnableRaisingEvents = true
             };
 
-            Plugin.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process);
+            ServerEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process);
 
             //Logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
 
@@ -537,7 +537,7 @@ namespace MediaBrowser.Api.Playback
             {
                 Logger.ErrorException("Error starting ffmpeg", ex);
 
-                Plugin.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType);
+                ServerEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType);
 
                 state.LogFileStream.Dispose();
 
@@ -588,7 +588,7 @@ namespace MediaBrowser.Api.Playback
 
             process.Dispose();
 
-            Plugin.Instance.OnTranscodingFinished(outputFilePath, TranscodingJobType);
+            ServerEntryPoint.Instance.OnTranscodingFinished(outputFilePath, TranscodingJobType);
 
             if (!exitCode.HasValue || exitCode.Value != 0)
             {

+ 2 - 2
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -77,7 +77,7 @@ namespace MediaBrowser.Api.Playback.Hls
             }
             else
             {
-                Plugin.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
+                ServerEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
             }
 
             // Get the current playlist text and convert to bytes
@@ -94,7 +94,7 @@ namespace MediaBrowser.Api.Playback.Hls
             }
             finally
             {
-                Plugin.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
+                ServerEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
             }
         }
 

+ 2 - 2
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -107,7 +107,7 @@ namespace MediaBrowser.Api.Playback.Progressive
 
             var outputPath = GetOutputFilePath(state);
 
-            if (File.Exists(outputPath) && !Plugin.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
+            if (File.Exists(outputPath) && !ServerEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
             {
                 return ToStaticFileResult(outputPath);
             }
@@ -133,7 +133,7 @@ namespace MediaBrowser.Api.Playback.Progressive
             }
             else
             {
-                Plugin.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
+                ServerEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
             }
 
             return new ProgressiveStreamWriter

+ 1 - 1
MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs

@@ -41,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Progressive
             }
             finally
             {
-                Plugin.Instance.OnTranscodeEndRequest(Path, TranscodingJobType.Progressive);
+                ServerEntryPoint.Instance.OnTranscodeEndRequest(Path, TranscodingJobType.Progressive);
             }
         }
 

+ 13 - 290
MediaBrowser.Api/Plugin.cs

@@ -1,12 +1,7 @@
-using MediaBrowser.Common.Plugins;
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Plugins;
 using MediaBrowser.Model.Plugins;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Api
 {
@@ -15,6 +10,16 @@ namespace MediaBrowser.Api
     /// </summary>
     public class Plugin : BasePlugin<BasePluginConfiguration>
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Plugin" /> class.
+        /// </summary>
+        /// <param name="kernel">The kernel.</param>
+        /// <param name="xmlSerializer">The XML serializer.</param>
+        public Plugin(IKernel kernel, IXmlSerializer xmlSerializer) : base(kernel, xmlSerializer)
+        {
+            Instance = this;
+        }
+
         /// <summary>
         /// Gets the name of the plugin
         /// </summary>
@@ -41,287 +46,5 @@ namespace MediaBrowser.Api
         /// </summary>
         /// <value>The instance.</value>
         public static Plugin Instance { get; private set; }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="Plugin" /> class.
-        /// </summary>
-        public Plugin()
-        {
-            Instance = 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 override void DisposeOnServer(bool dispose)
-        {
-            if (dispose)
-            {
-                var jobCount = ActiveTranscodingJobs.Count;
-
-                Parallel.ForEach(ActiveTranscodingJobs, OnTranscodeKillTimerStopped);
-             
-                // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
-                if (jobCount > 0)
-                {
-                    Thread.Sleep(1000);
-                }
-            }
-
-            base.DisposeOnServer(dispose);
-        }
-
-        /// <summary>
-        /// The active transcoding jobs
-        /// </summary>
-        private readonly List<TranscodingJob> ActiveTranscodingJobs = new List<TranscodingJob>();
-
-        /// <summary>
-        /// Called when [transcode beginning].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="process">The process.</param>
-        public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process)
-        {
-            lock (ActiveTranscodingJobs)
-            {
-                ActiveTranscodingJobs.Add(new TranscodingJob
-                {
-                    Type = type,
-                    Path = path,
-                    Process = process,
-                    ActiveRequestCount = 1
-                });
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode failed to start].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        public void OnTranscodeFailedToStart(string path, TranscodingJobType type)
-        {
-            lock (ActiveTranscodingJobs)
-            {
-                var job = ActiveTranscodingJobs.First(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
-
-                ActiveTranscodingJobs.Remove(job);
-            }
-        }
-
-        /// <summary>
-        /// Determines whether [has active transcoding job] [the specified path].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        /// <returns><c>true</c> if [has active transcoding job] [the specified path]; otherwise, <c>false</c>.</returns>
-        public bool HasActiveTranscodingJob(string path, TranscodingJobType type)
-        {
-            lock (ActiveTranscodingJobs)
-            {
-                return ActiveTranscodingJobs.Any(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode begin request].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        public void OnTranscodeBeginRequest(string path, TranscodingJobType type)
-        {
-            lock (ActiveTranscodingJobs)
-            {
-                var job = ActiveTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
-
-                if (job == null)
-                {
-                    return;
-                }
-
-                job.ActiveRequestCount++;
-
-                if (job.KillTimer != null)
-                {
-                    job.KillTimer.Dispose();
-                    job.KillTimer = null;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode end request].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        public void OnTranscodeEndRequest(string path, TranscodingJobType type)
-        {
-            lock (ActiveTranscodingJobs)
-            {
-                var job = ActiveTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
-
-                if (job == null)
-                {
-                    return;   
-                }
-
-                job.ActiveRequestCount--;
-
-                if (job.ActiveRequestCount == 0)
-                {
-                    var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 30000;
-
-                    if (job.KillTimer == null)
-                    {
-                        job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
-                    }
-                    else
-                    {
-                        job.KillTimer.Change(timerDuration, Timeout.Infinite);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcoding finished].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        public void OnTranscodingFinished(string path, TranscodingJobType type)
-        {
-            lock (ActiveTranscodingJobs)
-            {
-                var job = ActiveTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
-
-                if (job == null)
-                {
-                    return;
-                }
-
-                ActiveTranscodingJobs.Remove(job);
-
-                if (job.KillTimer != null)
-                {
-                    job.KillTimer.Dispose();
-                    job.KillTimer = null;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode kill timer stopped].
-        /// </summary>
-        /// <param name="state">The state.</param>
-        private void OnTranscodeKillTimerStopped(object state)
-        {
-            var job = (TranscodingJob)state;
-
-            lock (ActiveTranscodingJobs)
-            {
-                ActiveTranscodingJobs.Remove(job);
-
-                if (job.KillTimer != null)
-                {
-                    job.KillTimer.Dispose();
-                    job.KillTimer = null;
-                }
-            }
-            
-            var process = job.Process;
-
-            var hasExited = true;
-
-            try
-            {
-                hasExited = process.HasExited;
-            }
-            catch (Win32Exception ex)
-            {
-                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
-            }
-            catch (InvalidOperationException ex)
-            {
-                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
-            }
-            catch (NotSupportedException ex)
-            {
-                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
-            }
-
-            if (hasExited)
-            {
-                return;
-            }
-
-            try
-            {
-                Logger.Info("Killing ffmpeg process for {0}", job.Path);
-
-                process.Kill();
-            }
-            catch (Win32Exception ex)
-            {
-                Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
-            }
-            catch (InvalidOperationException ex)
-            {
-                Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
-            }
-            catch (NotSupportedException ex)
-            {
-                Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
-            }
-        }
-    }
-
-    /// <summary>
-    /// Class TranscodingJob
-    /// </summary>
-    public class TranscodingJob
-    {
-        /// <summary>
-        /// Gets or sets the path.
-        /// </summary>
-        /// <value>The path.</value>
-        public string Path { get; set; }
-        /// <summary>
-        /// Gets or sets the type.
-        /// </summary>
-        /// <value>The type.</value>
-        public TranscodingJobType Type { get; set; }
-        /// <summary>
-        /// Gets or sets the process.
-        /// </summary>
-        /// <value>The process.</value>
-        public Process Process { get; set; }
-        /// <summary>
-        /// Gets or sets the active request count.
-        /// </summary>
-        /// <value>The active request count.</value>
-        public int ActiveRequestCount { get; set; }
-        /// <summary>
-        /// Gets or sets the kill timer.
-        /// </summary>
-        /// <value>The kill timer.</value>
-        public Timer KillTimer { get; set; }
-    }
-
-    /// <summary>
-    /// Enum TranscodingJobType
-    /// </summary>
-    public enum TranscodingJobType
-    {
-        /// <summary>
-        /// The progressive
-        /// </summary>
-        Progressive,
-        /// <summary>
-        /// The HLS
-        /// </summary>
-        Hls
     }
 }

+ 15 - 7
MediaBrowser.Api/PluginService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Implementations.HttpServer;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Plugins;
@@ -123,12 +124,18 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly IJsonSerializer _jsonSerializer;
 
+        /// <summary>
+        /// The _app host
+        /// </summary>
+        private readonly IApplicationHost _appHost;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="PluginService" /> class.
         /// </summary>
         /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="appHost">The app host.</param>
         /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
-        public PluginService(IJsonSerializer jsonSerializer)
+        public PluginService(IJsonSerializer jsonSerializer, IApplicationHost appHost)
             : base()
         {
             if (jsonSerializer == null)
@@ -136,6 +143,7 @@ namespace MediaBrowser.Api
                 throw new ArgumentNullException("jsonSerializer");
             }
 
+            _appHost = appHost;
             _jsonSerializer = jsonSerializer;
         }
 
@@ -146,7 +154,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetPlugins request)
         {
-            var result = Kernel.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToList();
+            var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToList();
             
             return ToOptimizedResult(result);
         }
@@ -158,7 +166,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetPluginAssembly request)
         {
-            var plugin = Kernel.Plugins.First(p => p.Id == request.Id);
+            var plugin = _appHost.Plugins.First(p => p.Id == request.Id);
 
             return ToStaticFileResult(plugin.AssemblyFilePath);
         }
@@ -170,7 +178,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetPluginConfiguration request)
         {
-            var plugin = Kernel.Plugins.First(p => p.Id == request.Id);
+            var plugin = _appHost.Plugins.First(p => p.Id == request.Id);
 
             var dateModified = plugin.ConfigurationDateLastModified;
 
@@ -186,7 +194,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetPluginConfigurationFile request)
         {
-            var plugin = Kernel.Plugins.First(p => p.Id == request.Id);
+            var plugin = _appHost.Plugins.First(p => p.Id == request.Id);
 
             return ToStaticFileResult(plugin.ConfigurationFilePath);
         }
@@ -235,7 +243,7 @@ namespace MediaBrowser.Api
             var pathInfo = PathInfo.Parse(Request.PathInfo);
             var id = new Guid(pathInfo.GetArgumentValue<string>(1));
 
-            var plugin = Kernel.Plugins.First(p => p.Id == id);
+            var plugin = _appHost.Plugins.First(p => p.Id == id);
 
             var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, plugin.ConfigurationType) as BasePluginConfiguration;
 
@@ -250,7 +258,7 @@ namespace MediaBrowser.Api
         {
             var kernel = (Kernel)Kernel;
 
-            var plugin = kernel.Plugins.First(p => p.Id == request.Id);
+            var plugin = _appHost.Plugins.First(p => p.Id == request.Id);
 
             kernel.InstallationManager.UninstallPlugin(plugin);
         }

+ 333 - 0
MediaBrowser.Api/ServerEntryPoint.cs

@@ -0,0 +1,333 @@
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api
+{
+    /// <summary>
+    /// Class ServerEntryPoint
+    /// </summary>
+    public class ServerEntryPoint : IServerEntryPoint
+    {
+        /// <summary>
+        /// The instance
+        /// </summary>
+        public static ServerEntryPoint Instance;
+
+        /// <summary>
+        /// Gets or sets the logger.
+        /// </summary>
+        /// <value>The logger.</value>
+        private ILogger Logger { get; set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ServerEntryPoint" /> class.
+        /// </summary>
+        /// <param name="logger">The logger.</param>
+        public ServerEntryPoint(ILogger logger)
+        {
+            Logger = logger;
+
+            Instance = this;
+        }
+
+        /// <summary>
+        /// Runs this instance.
+        /// </summary>
+        public void Run()
+        {
+        }
+
+        /// <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)
+        {
+            var jobCount = ActiveTranscodingJobs.Count;
+
+            Parallel.ForEach(ActiveTranscodingJobs, OnTranscodeKillTimerStopped);
+
+            // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
+            if (jobCount > 0)
+            {
+                Thread.Sleep(1000);
+            }
+        }
+
+        /// <summary>
+        /// The active transcoding jobs
+        /// </summary>
+        private readonly List<TranscodingJob> ActiveTranscodingJobs = new List<TranscodingJob>();
+
+        /// <summary>
+        /// Called when [transcode beginning].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="process">The process.</param>
+        public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process)
+        {
+            lock (ActiveTranscodingJobs)
+            {
+                ActiveTranscodingJobs.Add(new TranscodingJob
+                {
+                    Type = type,
+                    Path = path,
+                    Process = process,
+                    ActiveRequestCount = 1
+                });
+            }
+        }
+
+        /// <summary>
+        /// <summary>
+        /// The progressive
+        /// </summary>
+        /// Called when [transcode failed to start].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="type">The type.</param>
+        public void OnTranscodeFailedToStart(string path, TranscodingJobType type)
+        {
+            lock (ActiveTranscodingJobs)
+            {
+                var job = ActiveTranscodingJobs.First(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
+
+                ActiveTranscodingJobs.Remove(job);
+            }
+        }
+
+        /// <summary>
+        /// Determines whether [has active transcoding job] [the specified path].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="type">The type.</param>
+        /// <returns><c>true</c> if [has active transcoding job] [the specified path]; otherwise, <c>false</c>.</returns>
+        public bool HasActiveTranscodingJob(string path, TranscodingJobType type)
+        {
+            lock (ActiveTranscodingJobs)
+            {
+                return ActiveTranscodingJobs.Any(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
+            }
+        }
+
+        /// <summary>
+        /// Called when [transcode begin request].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="type">The type.</param>
+        public void OnTranscodeBeginRequest(string path, TranscodingJobType type)
+        {
+            lock (ActiveTranscodingJobs)
+            {
+                var job = ActiveTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
+
+                if (job == null)
+                {
+                    return;
+                }
+
+                job.ActiveRequestCount++;
+
+                if (job.KillTimer != null)
+                {
+                    job.KillTimer.Dispose();
+                    job.KillTimer = null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Called when [transcode end request].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="type">The type.</param>
+        public void OnTranscodeEndRequest(string path, TranscodingJobType type)
+        {
+            lock (ActiveTranscodingJobs)
+            {
+                var job = ActiveTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
+
+                if (job == null)
+                {
+                    return;
+                }
+
+                job.ActiveRequestCount--;
+
+                if (job.ActiveRequestCount == 0)
+                {
+                    var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 30000;
+
+                    if (job.KillTimer == null)
+                    {
+                        job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
+                    }
+                    else
+                    {
+                        job.KillTimer.Change(timerDuration, Timeout.Infinite);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Called when [transcoding finished].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="type">The type.</param>
+        public void OnTranscodingFinished(string path, TranscodingJobType type)
+        {
+            lock (ActiveTranscodingJobs)
+            {
+                var job = ActiveTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
+
+                if (job == null)
+                {
+                    return;
+                }
+
+                ActiveTranscodingJobs.Remove(job);
+
+                if (job.KillTimer != null)
+                {
+                    job.KillTimer.Dispose();
+                    job.KillTimer = null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Called when [transcode kill timer stopped].
+        /// </summary>
+        /// <param name="state">The state.</param>
+        private void OnTranscodeKillTimerStopped(object state)
+        {
+            var job = (TranscodingJob)state;
+
+            lock (ActiveTranscodingJobs)
+            {
+                ActiveTranscodingJobs.Remove(job);
+
+                if (job.KillTimer != null)
+                {
+                    job.KillTimer.Dispose();
+                    job.KillTimer = null;
+                }
+            }
+
+            var process = job.Process;
+
+            var hasExited = true;
+
+            try
+            {
+                hasExited = process.HasExited;
+            }
+            catch (Win32Exception ex)
+            {
+                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
+            }
+            catch (InvalidOperationException ex)
+            {
+                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
+            }
+            catch (NotSupportedException ex)
+            {
+                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
+            }
+
+            if (hasExited)
+            {
+                return;
+            }
+
+            try
+            {
+                Logger.Info("Killing ffmpeg process for {0}", job.Path);
+
+                process.Kill();
+            }
+            catch (Win32Exception ex)
+            {
+                Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
+            }
+            catch (InvalidOperationException ex)
+            {
+                Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
+            }
+            catch (NotSupportedException ex)
+            {
+                Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
+            }
+        }
+
+    }
+
+    /// <summary>
+    /// Class TranscodingJob
+    /// </summary>
+    public class TranscodingJob
+    {
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
+        public string Path { get; set; }
+        /// <summary>
+        /// Gets or sets the type.
+        /// </summary>
+        /// <value>The type.</value>
+        public TranscodingJobType Type { get; set; }
+        /// <summary>
+        /// Gets or sets the process.
+        /// </summary>
+        /// <value>The process.</value>
+        public Process Process { get; set; }
+        /// <summary>
+        /// Gets or sets the active request count.
+        /// </summary>
+        /// <value>The active request count.</value>
+        public int ActiveRequestCount { get; set; }
+        /// <summary>
+        /// <summary>
+        /// Enum TranscodingJobType
+        /// </summary>
+        /// <summary>
+        /// Gets or sets the kill timer.
+        /// </summary>
+        /// <value>The kill timer.</value>
+        public Timer KillTimer { get; set; }
+    }
+
+    /// <summary>
+    /// Enum TranscodingJobType
+    /// </summary>
+    public enum TranscodingJobType
+    {
+        /// <summary>
+        /// The progressive
+        /// </summary>
+        Progressive,
+        /// <summary>
+        /// The HLS
+        /// </summary>
+        Hls
+    }
+}

+ 21 - 2
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Common.Implementations.Updates;
 using MediaBrowser.Common.Implementations.WebSocket;
 using MediaBrowser.Common.Kernel;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Model.Logging;
@@ -25,6 +26,12 @@ namespace MediaBrowser.Common.Implementations
         /// <value>The logger.</value>
         public ILogger Logger { get; protected set; }
 
+        /// <summary>
+        /// Gets or sets the plugins.
+        /// </summary>
+        /// <value>The plugins.</value>
+        public IEnumerable<IPlugin> Plugins { get; protected set; }
+
         /// <summary>
         /// Gets or sets the log manager.
         /// </summary>
@@ -142,12 +149,13 @@ namespace MediaBrowser.Common.Implementations
         /// </summary>
         protected virtual void FindParts()
         {
-            Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
-
             Resolve<IHttpServer>().Init(GetExports<IRestfulService>(false));
             Resolve<IServerManager>().AddWebSocketListeners(GetExports<IWebSocketListener>(false));
 
             Resolve<IServerManager>().Start();
+            Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
+
+            Plugins = GetExports<IPlugin>();
         }
         
         /// <summary>
@@ -348,6 +356,17 @@ namespace MediaBrowser.Common.Implementations
             
         }
 
+        /// <summary>
+        /// Removes the plugin.
+        /// </summary>
+        /// <param name="plugin">The plugin.</param>
+        public void RemovePlugin(IPlugin plugin)
+        {
+            var list = Plugins.ToList();
+            list.Remove(plugin);
+            Plugins = list;
+        }
+
         /// <summary>
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// </summary>

+ 3 - 77
MediaBrowser.Common/Kernel/BaseKernel.cs

@@ -1,16 +1,13 @@
 using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Security;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
 using System;
-using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Common.Kernel
 {
@@ -121,12 +118,6 @@ namespace MediaBrowser.Common.Kernel
         /// <value>The application paths.</value>
         public TApplicationPathsType ApplicationPaths { get; private set; }
 
-        /// <summary>
-        /// Gets the list of currently loaded plugins
-        /// </summary>
-        /// <value>The plugins.</value>
-        public IEnumerable<IPlugin> Plugins { get; protected set; }
-
         /// <summary>
         /// Gets or sets the TCP manager.
         /// </summary>
@@ -211,9 +202,9 @@ namespace MediaBrowser.Common.Kernel
         /// Initializes the Kernel
         /// </summary>
         /// <returns>Task.</returns>
-        public async Task Init()
+        public void Init()
         {
-            await ReloadInternal().ConfigureAwait(false);
+            ReloadInternal();
 
             OnReloadCompleted();
 
@@ -224,64 +215,11 @@ namespace MediaBrowser.Common.Kernel
         /// Performs initializations that can be reloaded at anytime
         /// </summary>
         /// <returns>Task.</returns>
-        protected virtual async Task ReloadInternal()
+        protected virtual void ReloadInternal()
         {
-            // Set these to null so that they can be lazy loaded again
-            Configuration = null;
-
-            await OnConfigurationLoaded().ConfigureAwait(false);
-
-            FindParts();
-
-            await OnComposablePartsLoaded().ConfigureAwait(false);
-
             ServerManager = ApplicationHost.Resolve<IServerManager>();
         }
 
-        /// <summary>
-        /// Called when [configuration loaded].
-        /// </summary>
-        /// <returns>Task.</returns>
-        protected virtual Task OnConfigurationLoaded()
-        {
-            return Task.FromResult<object>(null);
-        }
-
-        /// <summary>
-        /// Composes the parts with ioc container.
-        /// </summary>
-        protected virtual void FindParts()
-        {
-            Plugins = ApplicationHost.GetExports<IPlugin>();
-        }
-
-        /// <summary>
-        /// Fires after MEF finishes finding composable parts within plugin assemblies
-        /// </summary>
-        /// <returns>Task.</returns>
-        protected virtual Task OnComposablePartsLoaded()
-        {
-            return Task.Run(() =>
-            {
-                // Start-up each plugin
-                Parallel.ForEach(Plugins, plugin =>
-                {
-                    Logger.Info("Initializing {0} {1}", plugin.Name, plugin.Version);
-
-                    try
-                    {
-                        plugin.Initialize(this, _xmlSerializer, Logger);
-
-                        Logger.Info("{0} {1} initialized.", plugin.Name, plugin.Version);
-                    }
-                    catch (Exception ex)
-                    {
-                        Logger.ErrorException("Error initializing {0}", ex, plugin.Name);
-                    }
-                });
-            });
-        }
-
         /// <summary>
         /// Notifies that the kernel that a change has been made that requires a restart
         /// </summary>
@@ -442,17 +380,5 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         /// <value>The resource pools.</value>
         public ResourcePool ResourcePools { get; set; }
-
-        /// <summary>
-        /// Removes the plugin.
-        /// </summary>
-        /// <param name="plugin">The plugin.</param>
-        public void RemovePlugin(IPlugin plugin)
-        {
-            var list = Plugins.ToList();
-            list.Remove(plugin);
-            Plugins = list;
-        }
-
     }
 }

+ 14 - 1
MediaBrowser.Common/Kernel/IApplicationHost.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Updates;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Model.Updates;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -97,5 +98,17 @@ namespace MediaBrowser.Common.Kernel
         /// Shuts down.
         /// </summary>
         void Shutdown();
+
+        /// <summary>
+        /// Gets the plugins.
+        /// </summary>
+        /// <value>The plugins.</value>
+        IEnumerable<IPlugin> Plugins { get; }
+
+        /// <summary>
+        /// Removes the plugin.
+        /// </summary>
+        /// <param name="plugin">The plugin.</param>
+        void RemovePlugin(IPlugin plugin);
     }
 }

+ 1 - 14
MediaBrowser.Common/Kernel/IKernel.cs

@@ -40,7 +40,7 @@ namespace MediaBrowser.Common.Kernel
         /// Inits this instance.
         /// </summary>
         /// <returns>Task.</returns>
-        Task Init();
+        void Init();
 
         /// <summary>
         /// Gets or sets a value indicating whether this instance has pending kernel reload.
@@ -71,12 +71,6 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         void PerformPendingRestart();
 
-        /// <summary>
-        /// Gets the plugins.
-        /// </summary>
-        /// <value>The plugins.</value>
-        IEnumerable<IPlugin> Plugins { get; }
-
         /// <summary>
         /// Gets the UDP server port number.
         /// </summary>
@@ -123,12 +117,5 @@ namespace MediaBrowser.Common.Kernel
         /// </summary>
         /// <value>The resource pools.</value>
         ResourcePool ResourcePools { get; set; }
-
-        /// <summary>
-        /// Removes the plugin.
-        /// </summary>
-        /// <param name="plugin">The plugin.</param>
-        void RemovePlugin(IPlugin plugin);
-
     }
 }

+ 16 - 80
MediaBrowser.Common/Plugins/BasePlugin.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Plugins;
 using MediaBrowser.Model.Serialization;
 using System;
@@ -14,7 +13,7 @@ namespace MediaBrowser.Common.Plugins
     /// Provides a common base class for all plugins
     /// </summary>
     /// <typeparam name="TConfigurationType">The type of the T configuration type.</typeparam>
-    public abstract class BasePlugin<TConfigurationType> : IDisposable, IPlugin
+    public abstract class BasePlugin<TConfigurationType> : IPlugin
         where TConfigurationType : BasePluginConfiguration
     {
         /// <summary>
@@ -23,6 +22,12 @@ namespace MediaBrowser.Common.Plugins
         /// <value>The kernel.</value>
         protected IKernel Kernel { get; private set; }
 
+        /// <summary>
+        /// Gets the XML serializer.
+        /// </summary>
+        /// <value>The XML serializer.</value>
+        protected IXmlSerializer XmlSerializer { get; private set; }
+        
         /// <summary>
         /// Gets or sets the plugin's current context
         /// </summary>
@@ -56,6 +61,12 @@ namespace MediaBrowser.Common.Plugins
             }
         }
 
+        /// <summary>
+        /// Gets a value indicating whether this instance is first run.
+        /// </summary>
+        /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
+        public bool IsFirstRun { get; private set; }
+
         /// <summary>
         /// Gets the type of configuration this plugin uses
         /// </summary>
@@ -252,87 +263,14 @@ namespace MediaBrowser.Common.Plugins
         }
 
         /// <summary>
-        /// Gets the logger.
-        /// </summary>
-        /// <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.
+        /// Initializes a new instance of the <see cref="BasePlugin{TConfigurationType}" /> class.
         /// </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, IXmlSerializer xmlSerializer, ILogger logger)
+        protected BasePlugin(IKernel kernel, IXmlSerializer xmlSerializer)
         {
-            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)
-            {
-                InitializeOnServer(!File.Exists(ConfigurationFilePath));
-            }
-        }
-
-        /// <summary>
-        /// Starts the plugin on the server
-        /// </summary>
-        /// <param name="isFirstRun">if set to <c>true</c> [is first run].</param>
-        protected virtual void InitializeOnServer(bool isFirstRun)
-        {
-        }
-
-        /// <summary>
-        /// Disposes the plugins. Undos all actions performed during Init.
-        /// </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 void Dispose(bool dispose)
-        {
-            if (Kernel.KernelContext == KernelContext.Server)
-            {
-                DisposeOnServer(dispose);
-            }
-        }
-
-        /// <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 DisposeOnServer(bool dispose)
-        {
-            
+            XmlSerializer = xmlSerializer;
         }
 
         /// <summary>
@@ -351,8 +289,6 @@ namespace MediaBrowser.Common.Plugins
                 throw new InvalidOperationException("Cannot call Plugin.SaveConfiguration from the UI.");
             }
 
-            Logger.Info("Saving configuration");
-
             lock (_configurationSaveLock)
             {
                 XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath);

+ 10 - 24
MediaBrowser.Common/Plugins/IPlugin.cs

@@ -1,11 +1,11 @@
-using MediaBrowser.Common.Kernel;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Plugins;
-using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Plugins;
 using System;
 
 namespace MediaBrowser.Common.Plugins
 {
+    /// <summary>
+    /// Interface IPlugin
+    /// </summary>
     public interface IPlugin
     {
         /// <summary>
@@ -92,26 +92,6 @@ namespace MediaBrowser.Common.Plugins
         /// <value>The data folder path.</value>
         string DataFolderPath { get; }
 
-        /// <summary>
-        /// Gets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
-        ILogger Logger { get; }
-
-        /// <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>
-        void Initialize(IKernel kernel, IXmlSerializer xmlSerializer, ILogger logger);
-
-        /// <summary>
-        /// Disposes the plugins. Undos all actions performed during Init.
-        /// </summary>
-        void Dispose();
-
         /// <summary>
         /// Saves the current configuration to the file system
         /// </summary>
@@ -136,5 +116,11 @@ namespace MediaBrowser.Common.Plugins
         /// Called when just before the plugin is uninstalled from the server.
         /// </summary>
         void OnUninstalling();
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is first run.
+        /// </summary>
+        /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
+        bool IsFirstRun { get; }
     }
 }

+ 1 - 1
MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs

@@ -16,7 +16,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             if (isApplicationStartup)
             {
-                await Task.Delay(2000).ConfigureAwait(false);
+                await Task.Delay(3000).ConfigureAwait(false);
 
                 OnTriggered();
             }

+ 14 - 10
MediaBrowser.Controller/Kernel.cs

@@ -183,7 +183,7 @@ namespace MediaBrowser.Controller
         /// <summary>
         /// Composes the parts with ioc container.
         /// </summary>
-        protected override void FindParts()
+        protected void FindParts()
         {
             // For now there's no real way to inject this properly
             BaseItem.LibraryManager = ApplicationHost.Resolve<ILibraryManager>();
@@ -194,8 +194,6 @@ namespace MediaBrowser.Controller
             ProviderManager = (ProviderManager)ApplicationHost.CreateInstance(typeof(ProviderManager));
             SecurityManager = (PluginSecurityManager)ApplicationHost.CreateInstance(typeof(PluginSecurityManager));
             
-            base.FindParts();
-
             UserDataRepositories = ApplicationHost.GetExports<IUserDataRepository>();
             UserRepositories = ApplicationHost.GetExports<IUserRepository>();
             DisplayPreferencesRepositories = ApplicationHost.GetExports<IDisplayPreferencesRepository>();
@@ -211,15 +209,24 @@ namespace MediaBrowser.Controller
         /// Performs initializations that can be reloaded at anytime
         /// </summary>
         /// <returns>Task.</returns>
-        protected override async Task ReloadInternal()
+        protected override async void ReloadInternal()
         {
-            await base.ReloadInternal().ConfigureAwait(false);
+            base.ReloadInternal();
+
+            FindParts();
+
+            await LoadRepositories().ConfigureAwait(false);
 
             ReloadResourcePools();
 
             ReloadFileSystemManager();
 
             await ApplicationHost.Resolve<IUserManager>().RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false);
+
+            foreach (var entryPoint in ApplicationHost.GetExports<IServerEntryPoint>())
+            {
+                entryPoint.Run();
+            }
         }
 
         /// <summary>
@@ -263,11 +270,8 @@ namespace MediaBrowser.Controller
         /// Called when [composable parts loaded].
         /// </summary>
         /// <returns>Task.</returns>
-        protected override async Task OnComposablePartsLoaded()
+        protected Task LoadRepositories()
         {
-            // The base class will start up all the plugins
-            await base.OnComposablePartsLoaded().ConfigureAwait(false);
-
             // Get the current item repository
             ItemRepository = GetRepository(ItemRepositories, Configuration.ItemRepository);
             var itemRepoTask = ItemRepository.Initialize();
@@ -284,7 +288,7 @@ namespace MediaBrowser.Controller
             DisplayPreferencesRepository = GetRepository(DisplayPreferencesRepositories, Configuration.DisplayPreferencesRepository);
             var displayPreferencesRepoTask = DisplayPreferencesRepository.Initialize();
 
-            await Task.WhenAll(itemRepoTask, userRepoTask, userDataRepoTask, displayPreferencesRepoTask).ConfigureAwait(false);
+            return Task.WhenAll(itemRepoTask, userRepoTask, userDataRepoTask, displayPreferencesRepoTask);
         }
 
         /// <summary>

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

@@ -131,6 +131,7 @@
     <Compile Include="Persistence\IUserRepository.cs" />
     <Compile Include="Library\IIntroProvider.cs" />
     <Compile Include="Plugins\IPluginConfigurationPage.cs" />
+    <Compile Include="Plugins\IServerEntryPoint.cs" />
     <Compile Include="Plugins\PluginSecurityManager.cs" />
     <Compile Include="Providers\FanartBaseProvider.cs" />
     <Compile Include="Providers\IImageEnhancer.cs" />

+ 15 - 0
MediaBrowser.Controller/Plugins/IServerEntryPoint.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace MediaBrowser.Controller.Plugins
+{
+    /// <summary>
+    /// Interface IServerEntryPoint
+    /// </summary>
+    public interface IServerEntryPoint : IDisposable
+    {
+        /// <summary>
+        /// Runs this instance.
+        /// </summary>
+        void Run();
+    }
+}

+ 3 - 3
MediaBrowser.Controller/Updates/InstallationManager.cs

@@ -287,7 +287,7 @@ namespace MediaBrowser.Controller.Updates
         {
             var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
 
-            var plugins = Kernel.Plugins;
+            var plugins = ApplicationHost.Plugins;
 
             if (withAutoUpdateEnabled)
             {
@@ -424,7 +424,7 @@ namespace MediaBrowser.Controller.Updates
             if (!(Path.GetExtension(package.targetFilename) ?? "").Equals(".zip", StringComparison.OrdinalIgnoreCase))
             {
                 // Set last update time if we were installed before
-                var plugin = Kernel.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
+                var plugin = ApplicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
 
                 if (plugin != null)
                 {
@@ -460,7 +460,7 @@ namespace MediaBrowser.Controller.Updates
             plugin.OnUninstalling();
 
             // Remove it the quick way for now
-            Kernel.RemovePlugin(plugin);
+            ApplicationHost.RemovePlugin(plugin);
 
             File.Delete(plugin.AssemblyFilePath);
 

+ 0 - 5
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -287,11 +287,6 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <exception cref="System.InvalidOperationException">Cannot create the root folder until plugins have loaded</exception>
         public AggregateFolder CreateRootFolder()
         {
-            if (Kernel.Plugins == null)
-            {
-                throw new InvalidOperationException("Cannot create the root folder until plugins have loaded");
-            }
-
             var rootFolderPath = Kernel.ApplicationPaths.RootFolderPath;
             var rootFolder = Kernel.ItemRepository.RetrieveItem(rootFolderPath.GetMBId(typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(rootFolderPath);
 

+ 1 - 1
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -34,7 +34,7 @@
   <ItemGroup>
     <Reference Include="BdInfo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.0\lib\net45\BdInfo.dll</HintPath>
+      <HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.2\lib\net45\BdInfo.dll</HintPath>
     </Reference>
     <Reference Include="MoreLinq">
       <HintPath>..\packages\morelinq.1.0.15631-beta\lib\net35\MoreLinq.dll</HintPath>

+ 1 - 1
MediaBrowser.Server.Implementations/packages.config

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="MediaBrowser.BdInfo" version="1.0.0.0" targetFramework="net45" />
+  <package id="MediaBrowser.BdInfo" version="1.0.0.2" targetFramework="net45" />
   <package id="morelinq" version="1.0.15631-beta" targetFramework="net45" />
   <package id="System.Data.SQLite" version="1.0.84.0" targetFramework="net45" />
 </packages>

+ 1 - 1
MediaBrowser.ServerApplication/App.xaml.cs

@@ -177,7 +177,7 @@ namespace MediaBrowser.ServerApplication
 
                 var now = DateTime.UtcNow;
 
-                await Kernel.Init();
+                Kernel.Init();
 
                 var done = (DateTime.UtcNow - now);
                 Logger.Info("Kernel.Init completed in {0}{1} minutes and {2} seconds.", done.Hours > 0 ? done.Hours + " Hours " : "", done.Minutes, done.Seconds);

+ 3 - 0
MediaBrowser.sln

@@ -253,4 +253,7 @@ Global
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(Performance) = preSolution
+		HasPerformanceSessions = true
+	EndGlobalSection
 EndGlobal

+ 5 - 4
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,16 +2,17 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.22</version>
-        <title />
+        <version>3.0.23</version>
+        <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
-        <owners>Media Browser Team</owners>
+        <owners>ebr,Luke,scottisafool</owners>
         <projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
 		<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
         <requireLicenseAcceptance>false</requireLicenseAcceptance>
         <description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
+        <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.22" />
+            <dependency id="MediaBrowser.Common" version="3.0.23" />
             <dependency id="NLog" version="2.0.0.2000" />
             <dependency id="ServiceStack" version="3.9.37" />
             <dependency id="ServiceStack.Api.Swagger" version="3.9.35" />

+ 3 - 2
Nuget/MediaBrowser.Common.nuspec

@@ -2,13 +2,14 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.22</version>
+        <version>3.0.23</version>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
-        <owners />
+        <owners>ebr,Luke,scottisafool</owners>
         <projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
 		<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
         <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <copyright>Copyright © Media Browser 2013</copyright>
         <description>Contains common model objects and interfaces used by all Media Browser solutions.</description>
     </metadata>
     <files>

+ 4 - 3
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,16 +2,17 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.22</version>
+        <version>3.0.23</version>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
-        <owners />
+        <owners>ebr,Luke,scottisafool</owners>
         <projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
 		<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
         <requireLicenseAcceptance>false</requireLicenseAcceptance>
         <description>Contains core components required to build plugins for Media Browser Server.</description>
+        <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.22" />
+            <dependency id="MediaBrowser.Common" version="3.0.23" />
         </dependencies>
     </metadata>
     <files>