aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/SystemService.cs8
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs4
-rw-r--r--MediaBrowser.Common/IApplicationHost.cs4
-rw-r--r--MediaBrowser.Common/Net/IServerManager.cs14
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs9
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs6
-rw-r--r--MediaBrowser.Model/System/SystemInfo.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs20
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs14
-rw-r--r--MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs34
-rw-r--r--MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs12
-rw-r--r--MediaBrowser.ServerApplication/App.xaml.cs154
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs36
-rw-r--r--MediaBrowser.ServerApplication/BackgroundService.cs30
-rw-r--r--MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs5
-rw-r--r--MediaBrowser.ServerApplication/IApplicationInterface.cs32
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs134
-rw-r--r--MediaBrowser.ServerApplication/MainWindow.xaml.cs14
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj8
20 files changed, 357 insertions, 191 deletions
diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs
index 3360e5e9e..9bbd6a588 100644
--- a/MediaBrowser.Api/SystemService.cs
+++ b/MediaBrowser.Api/SystemService.cs
@@ -133,8 +133,8 @@ namespace MediaBrowser.Api
{
Task.Run(async () =>
{
- await Task.Delay(100);
- _appHost.Restart();
+ await Task.Delay(100).ConfigureAwait(false);
+ await _appHost.Restart().ConfigureAwait(false);
});
}
@@ -146,8 +146,8 @@ namespace MediaBrowser.Api
{
Task.Run(async () =>
{
- await Task.Delay(100);
- _appHost.Shutdown();
+ await Task.Delay(100).ConfigureAwait(false);
+ await _appHost.Shutdown().ConfigureAwait(false);
});
}
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index bae2f9f07..f333eb22c 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -552,7 +552,7 @@ namespace MediaBrowser.Common.Implementations
/// <summary>
/// Restarts this instance.
/// </summary>
- public abstract void Restart();
+ public abstract Task Restart();
/// <summary>
/// Gets or sets a value indicating whether this instance can self update.
@@ -582,7 +582,7 @@ namespace MediaBrowser.Common.Implementations
/// <summary>
/// Shuts down.
/// </summary>
- public abstract void Shutdown();
+ public abstract Task Shutdown();
/// <summary>
/// Called when [application updated].
diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs
index 1ff28d924..7cb58f580 100644
--- a/MediaBrowser.Common/IApplicationHost.cs
+++ b/MediaBrowser.Common/IApplicationHost.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Common
/// <summary>
/// Restarts this instance.
/// </summary>
- void Restart();
+ Task Restart();
/// <summary>
/// Gets the application version.
@@ -113,7 +113,7 @@ namespace MediaBrowser.Common
/// <summary>
/// Shuts down.
/// </summary>
- void Shutdown();
+ Task Shutdown();
/// <summary>
/// Gets the plugins.
diff --git a/MediaBrowser.Common/Net/IServerManager.cs b/MediaBrowser.Common/Net/IServerManager.cs
index 3234e7060..32be88a34 100644
--- a/MediaBrowser.Common/Net/IServerManager.cs
+++ b/MediaBrowser.Common/Net/IServerManager.cs
@@ -5,6 +5,9 @@ using System.Threading.Tasks;
namespace MediaBrowser.Common.Net
{
+ /// <summary>
+ /// Interface IServerManager
+ /// </summary>
public interface IServerManager : IDisposable
{
/// <summary>
@@ -22,7 +25,14 @@ namespace MediaBrowser.Common.Net
/// <summary>
/// Starts this instance.
/// </summary>
- void Start();
+ /// <param name="urlPrefix">The URL prefix.</param>
+ /// <param name="enableHttpLogging">if set to <c>true</c> [enable HTTP logging].</param>
+ void Start(string urlPrefix, bool enableHttpLogging);
+
+ /// <summary>
+ /// Starts the web socket server.
+ /// </summary>
+ void StartWebSocketServer();
/// <summary>
/// Sends a message to all clients currently connected via a web socket
@@ -62,7 +72,7 @@ namespace MediaBrowser.Common.Net
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SendWebSocketMessageAsync<T>(string messageType, Func<T> dataFunction, IEnumerable<IWebSocketConnection> connections, CancellationToken cancellationToken);
-
+
/// <summary>
/// Adds the web socket listeners.
/// </summary>
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index c7df48c04..e4c68a8ab 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -77,5 +77,14 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="toStream">To stream.</param>
/// <returns>Task.</returns>
Task ProcessImage(ImageProcessingOptions options, Stream toStream);
+
+ /// <summary>
+ /// Gets the enhanced image.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>Task{System.String}.</returns>
+ Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex);
}
}
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index f96c2536e..495147125 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -25,5 +25,11 @@ namespace MediaBrowser.Controller
/// </summary>
/// <value>The HTTP server URL prefix.</value>
string HttpServerUrlPrefix { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is background service.
+ /// </summary>
+ /// <value><c>true</c> if this instance is background service; otherwise, <c>false</c>.</value>
+ bool IsBackgroundService { get; }
}
}
diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs
index f77856c6e..b00d7f29d 100644
--- a/MediaBrowser.Model/System/SystemInfo.cs
+++ b/MediaBrowser.Model/System/SystemInfo.cs
@@ -81,7 +81,13 @@ namespace MediaBrowser.Model.System
public int HttpServerPortNumber { get; set; }
/// <summary>
- /// Initializes a new instance of the <see cref="SystemInfo"/> class.
+ /// Gets or sets a value indicating whether this instance is background service.
+ /// </summary>
+ /// <value><c>true</c> if this instance is background service; otherwise, <c>false</c>.</value>
+ public bool IsBackgroundService { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SystemInfo" /> class.
/// </summary>
public SystemInfo()
{
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index c9f9af4f2..6458435ba 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -539,6 +539,26 @@ namespace MediaBrowser.Server.Implementations.Drawing
return string.Join("|", cacheKeys.ToArray()).GetMD5();
}
+ /// <summary>
+ /// Gets the enhanced image.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>Task{System.String}.</returns>
+ public async Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex)
+ {
+ var enhancers = GetSupportedEnhancers(item, imageType).ToList();
+
+ var imagePath = item.GetImagePath(imageType, imageIndex);
+
+ var dateModified = item.GetImageDateModified(imagePath);
+
+ var result = await GetEnhancedImage(imagePath, dateModified, item, imageType, imageIndex, enhancers);
+
+ return result.Item1;
+ }
+
private async Task<Tuple<string, DateTime>> GetEnhancedImage(string originalImagePath, DateTime dateModified, BaseItem item,
ImageType imageType, int imageIndex,
List<IImageEnhancer> enhancers)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs
index aa30cee26..7792a28bb 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs
@@ -529,7 +529,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
new ClientWebSocket();
- _supportsNativeWebSocket = true;
+ _supportsNativeWebSocket = false;
}
catch (PlatformNotSupportedException)
{
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index bf6526538..f6fd11960 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
@@ -69,7 +70,16 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
foreach (var fullName in Directory.EnumerateFiles(path))
{
- if (EntityResolutionHelper.IsAudioFile(fullName)) foundAudio++;
+ if (EntityResolutionHelper.IsAudioFile(fullName))
+ {
+ // Don't resolve these into audio files
+ if (string.Equals(Path.GetFileNameWithoutExtension(fullName), BaseItem.ThemeSongFilename) && EntityResolutionHelper.IsAudioFile(fullName))
+ {
+ continue;
+ }
+
+ foundAudio++;
+ }
if (foundAudio >= 2)
{
return true;
diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
index b63cf0031..a840ae214 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
@@ -118,43 +118,44 @@ namespace MediaBrowser.Server.Implementations.ServerManager
_jsonSerializer = jsonSerializer;
_applicationHost = applicationHost;
ConfigurationManager = configurationManager;
-
- ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
}
/// <summary>
/// Starts this instance.
/// </summary>
- public void Start()
+ public void Start(string urlPrefix, bool enableHttpLogging)
{
- ReloadHttpServer();
+ ReloadHttpServer(urlPrefix, enableHttpLogging);
+ }
+ public void StartWebSocketServer()
+ {
if (!SupportsNativeWebSocket)
{
- ReloadExternalWebSocketServer();
+ ReloadExternalWebSocketServer(ConfigurationManager.Configuration.LegacyWebSocketPortNumber);
}
}
/// <summary>
/// Starts the external web socket server.
/// </summary>
- private void ReloadExternalWebSocketServer()
+ private void ReloadExternalWebSocketServer(int portNumber)
{
DisposeExternalWebSocketServer();
ExternalWebSocketServer = _applicationHost.Resolve<IWebSocketServer>();
- ExternalWebSocketServer.Start(ConfigurationManager.Configuration.LegacyWebSocketPortNumber);
+ ExternalWebSocketServer.Start(portNumber);
ExternalWebSocketServer.WebSocketConnected += HttpServer_WebSocketConnected;
}
/// <summary>
/// Restarts the Http Server, or starts it if not currently running
/// </summary>
- private void ReloadHttpServer()
+ private void ReloadHttpServer(string urlPrefix, bool enableHttpLogging)
{
// Only reload if the port has changed, so that we don't disconnect any active users
- if (HttpServer != null && HttpServer.UrlPrefix.Equals(_applicationHost.HttpServerUrlPrefix, StringComparison.OrdinalIgnoreCase))
+ if (HttpServer != null && HttpServer.UrlPrefix.Equals(urlPrefix, StringComparison.OrdinalIgnoreCase))
{
return;
}
@@ -166,8 +167,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager
try
{
HttpServer = _applicationHost.Resolve<IHttpServer>();
- HttpServer.EnableHttpRequestLogging = ConfigurationManager.Configuration.EnableHttpLevelLogging;
- HttpServer.Start(_applicationHost.HttpServerUrlPrefix);
+ HttpServer.EnableHttpRequestLogging = enableHttpLogging;
+ HttpServer.Start(urlPrefix);
}
catch (SocketException ex)
{
@@ -376,17 +377,6 @@ namespace MediaBrowser.Server.Implementations.ServerManager
}
/// <summary>
- /// Handles the ConfigurationUpdated event of the _kernel control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- /// <exception cref="System.NotImplementedException"></exception>
- void ConfigurationUpdated(object sender, EventArgs e)
- {
- HttpServer.EnableHttpRequestLogging = ConfigurationManager.Configuration.EnableHttpLevelLogging;
- }
-
- /// <summary>
/// Adds the web socket listeners.
/// </summary>
/// <param name="listeners">The listeners.</param>
diff --git a/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs b/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs
index 6649fd197..1470a209e 100644
--- a/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs
+++ b/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs
@@ -55,14 +55,14 @@ namespace MediaBrowser.Server.Implementations.WebSocket
/// <param name="portNumber">The port number.</param>
public void Start(int portNumber)
{
- WebSocketServer = new WebSocketServer(portNumber, IPAddress.Any)
- {
- OnConnected = OnAlchemyWebSocketClientConnected,
- TimeOut = TimeSpan.FromHours(12)
- };
-
try
{
+ WebSocketServer = new WebSocketServer(portNumber, IPAddress.Any)
+ {
+ OnConnected = OnAlchemyWebSocketClientConnected,
+ TimeOut = TimeSpan.FromHours(12)
+ };
+
WebSocketServer.Start();
}
catch (SocketException ex)
diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs
index 362dd4bc0..42045257a 100644
--- a/MediaBrowser.ServerApplication/App.xaml.cs
+++ b/MediaBrowser.ServerApplication/App.xaml.cs
@@ -1,90 +1,20 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Constants;
-using MediaBrowser.Common.Implementations.Updates;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations;
using MediaBrowser.ServerApplication.Splash;
-using Microsoft.Win32;
using System;
using System.Diagnostics;
-using System.IO;
-using System.Net.Cache;
-using System.Threading;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
namespace MediaBrowser.ServerApplication
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
- public partial class App : Application
+ public partial class App : Application, IApplicationInterface
{
/// <summary>
- /// The single instance mutex
- /// </summary>
- private static Mutex _singleInstanceMutex;
-
- /// <summary>
- /// Defines the entry point of the application.
- /// </summary>
- [STAThread]
- public static void Main()
- {
- bool createdNew;
-
- var runningPath = Process.GetCurrentProcess().MainModule.FileName.Replace(Path.DirectorySeparatorChar.ToString(), string.Empty);
-
- _singleInstanceMutex = new Mutex(true, @"Local\" + runningPath, out createdNew);
-
- if (!createdNew)
- {
- _singleInstanceMutex = null;
- return;
- }
-
- // Look for the existence of an update archive
- var appPaths = new ServerApplicationPaths();
- var updateArchive = Path.Combine(appPaths.TempUpdatePath, Constants.MbServerPkgName + ".zip");
- if (File.Exists(updateArchive))
- {
- // Update is there - execute update
- try
- {
- new ApplicationUpdater().UpdateApplication(MBApplication.MBServer, appPaths, updateArchive);
-
- // And just let the app exit so it can update
- return;
- }
- catch (Exception e)
- {
- MessageBox.Show(string.Format("Error attempting to update application.\n\n{0}\n\n{1}", e.GetType().Name, e.Message));
- }
- }
-
- var application = new App();
-
- application.Run();
- }
-
- /// <summary>
- /// Gets the instance.
- /// </summary>
- /// <value>The instance.</value>
- public static App Instance
- {
- get
- {
- return Current as App;
- }
- }
-
- /// <summary>
/// Gets or sets the logger.
/// </summary>
/// <value>The logger.</value>
@@ -95,7 +25,7 @@ namespace MediaBrowser.ServerApplication
/// </summary>
/// <value>The composition root.</value>
protected ApplicationHost CompositionRoot { get; set; }
-
+
/// <summary>
/// Initializes a new instance of the <see cref="App" /> class.
/// </summary>
@@ -105,6 +35,11 @@ namespace MediaBrowser.ServerApplication
InitializeComponent();
}
+ public bool IsBackgroundService
+ {
+ get { return false; }
+ }
+
/// <summary>
/// Gets the name of the uninstaller file.
/// </summary>
@@ -114,63 +49,35 @@ namespace MediaBrowser.ServerApplication
get { return "MediaBrowser.Server.Uninstall.exe"; }
}
- /// <summary>
- /// Raises the <see cref="E:System.Windows.Application.Startup" /> event.
- /// </summary>
- /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the event data.</param>
- protected override void OnStartup(StartupEventArgs e)
+ public void OnUnhandledException(Exception ex)
{
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- LoadKernel();
+ Logger.ErrorException("UnhandledException", ex);
- SystemEvents.SessionEnding += SystemEvents_SessionEnding;
+ MessageBox.Show("Unhandled exception: " + ex.Message);
}
- /// <summary>
- /// Handles the UnhandledException event of the CurrentDomain control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="UnhandledExceptionEventArgs" /> instance containing the event data.</param>
- void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ protected override void OnStartup(StartupEventArgs e)
{
- var exception = (Exception)e.ExceptionObject;
-
- Logger.ErrorException("UnhandledException", exception);
+ base.OnStartup(e);
- MessageBox.Show("Unhandled exception: " + exception.Message);
-
- if (!Debugger.IsAttached)
- {
- Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(exception));
- }
- }
-
- /// <summary>
- /// Handles the SessionEnding event of the SystemEvents control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="SessionEndingEventArgs" /> instance containing the event data.</param>
- void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
- {
- // Try to shut down gracefully
- Shutdown();
+ LoadApplication();
}
/// <summary>
/// Loads the kernel.
/// </summary>
- protected async void LoadKernel()
+ protected async void LoadApplication()
{
try
{
- CompositionRoot = new ApplicationHost();
+ CompositionRoot = new ApplicationHost(this);
Logger = CompositionRoot.LogManager.GetLogger("App");
var splash = new SplashWindow(CompositionRoot.ApplicationVersion);
splash.Show();
-
+
await CompositionRoot.Init();
splash.Hide();
@@ -192,13 +99,18 @@ namespace MediaBrowser.ServerApplication
}
}
+ public void ShutdownApplication()
+ {
+ Dispatcher.Invoke(Shutdown);
+ }
+
/// <summary>
/// Raises the <see cref="E:System.Windows.Application.Exit" /> event.
/// </summary>
/// <param name="e">An <see cref="T:System.Windows.ExitEventArgs" /> that contains the event data.</param>
protected override void OnExit(ExitEventArgs e)
{
- ReleaseMutex();
+ MainStartup.ReleaseMutex();
base.OnExit(e);
@@ -209,22 +121,6 @@ namespace MediaBrowser.ServerApplication
}
/// <summary>
- /// Releases the mutex.
- /// </summary>
- private void ReleaseMutex()
- {
- if (_singleInstanceMutex == null)
- {
- return;
- }
-
- _singleInstanceMutex.ReleaseMutex();
- _singleInstanceMutex.Close();
- _singleInstanceMutex.Dispose();
- _singleInstanceMutex = null;
- }
-
- /// <summary>
/// Opens the dashboard page.
/// </summary>
/// <param name="page">The page.</param>
@@ -281,9 +177,9 @@ namespace MediaBrowser.ServerApplication
/// Restarts this instance.
/// </summary>
/// <exception cref="System.NotImplementedException"></exception>
- public void Restart()
+ public void RestartApplication()
{
- Dispatcher.Invoke(ReleaseMutex);
+ Dispatcher.Invoke(MainStartup.ReleaseMutex);
CompositionRoot.Dispose();
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 126bea9e5..7288d70d9 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Implementations;
using MediaBrowser.Common.Implementations.IO;
using MediaBrowser.Common.Implementations.ScheduledTasks;
-using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -183,6 +182,13 @@ namespace MediaBrowser.ServerApplication
private IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
+ public bool IsBackgroundService
+ {
+ get { return _appInterface != null && _appInterface.IsBackgroundService; }
+ }
+
+ private readonly IApplicationInterface _appInterface;
+
/// <summary>
/// The full path to our startmenu shortcut
/// </summary>
@@ -193,6 +199,11 @@ namespace MediaBrowser.ServerApplication
private Task<IHttpServer> _httpServerCreationTask;
+ public ApplicationHost(IApplicationInterface appInterface)
+ {
+ _appInterface = appInterface;
+ }
+
/// <summary>
/// Runs the startup tasks.
/// </summary>
@@ -475,7 +486,7 @@ namespace MediaBrowser.ServerApplication
{
try
{
- ServerManager.Start();
+ ServerManager.Start(HttpServerUrlPrefix, ServerConfigurationManager.Configuration.EnableHttpLevelLogging);
}
catch
{
@@ -490,6 +501,8 @@ namespace MediaBrowser.ServerApplication
throw;
}
}
+
+ ServerManager.StartWebSocketServer();
}
/// <summary>
@@ -501,6 +514,8 @@ namespace MediaBrowser.ServerApplication
{
base.OnConfigurationUpdated(sender, e);
+ HttpServer.EnableHttpRequestLogging = ServerConfigurationManager.Configuration.EnableHttpLevelLogging;
+
if (!string.Equals(HttpServer.UrlPrefix, HttpServerUrlPrefix, StringComparison.OrdinalIgnoreCase))
{
NotifyPendingRestart();
@@ -516,19 +531,18 @@ namespace MediaBrowser.ServerApplication
/// <summary>
/// Restarts this instance.
/// </summary>
- public override void Restart()
+ public override async Task Restart()
{
try
{
- var task = ServerManager.SendWebSocketMessageAsync("ServerRestarting", () => string.Empty, CancellationToken.None);
- task.Wait();
+ await ServerManager.SendWebSocketMessageAsync("ServerRestarting", () => string.Empty, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error sending server restart web socket message", ex);
}
- App.Instance.Restart();
+ _appInterface.RestartApplication();
}
/// <summary>
@@ -613,7 +627,8 @@ namespace MediaBrowser.ServerApplication
Id = _systemId,
ProgramDataPath = ApplicationPaths.ProgramDataPath,
MacAddress = GetMacAddress(),
- HttpServerPortNumber = ServerConfigurationManager.Configuration.HttpServerPortNumber
+ HttpServerPortNumber = ServerConfigurationManager.Configuration.HttpServerPortNumber,
+ IsBackgroundService = IsBackgroundService
};
}
@@ -637,19 +652,18 @@ namespace MediaBrowser.ServerApplication
/// <summary>
/// Shuts down.
/// </summary>
- public override void Shutdown()
+ public override async Task Shutdown()
{
try
{
- var task = ServerManager.SendWebSocketMessageAsync("ServerShuttingDown", () => string.Empty, CancellationToken.None);
- task.Wait();
+ await ServerManager.SendWebSocketMessageAsync("ServerShuttingDown", () => string.Empty, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error sending server shutdown web socket message", ex);
}
- App.Instance.Dispatcher.Invoke(App.Instance.Shutdown);
+ _appInterface.ShutdownApplication();
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/BackgroundService.cs b/MediaBrowser.ServerApplication/BackgroundService.cs
new file mode 100644
index 000000000..a8a9a5b50
--- /dev/null
+++ b/MediaBrowser.ServerApplication/BackgroundService.cs
@@ -0,0 +1,30 @@
+using System.ServiceProcess;
+
+namespace MediaBrowser.ServerApplication
+{
+ public class BackgroundService : ServiceBase
+ {
+ public BackgroundService()
+ {
+ CanPauseAndContinue = false;
+ CanHandleSessionChangeEvent = true;
+ CanStop = false;
+ CanShutdown = true;
+ ServiceName = "Media Browser";
+ }
+
+ protected override void OnSessionChange(SessionChangeDescription changeDescription)
+ {
+ base.OnSessionChange(changeDescription);
+ }
+
+ protected override void OnStart(string[] args)
+ {
+ }
+
+ protected override void OnShutdown()
+ {
+ base.OnShutdown();
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs b/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs
index 87578ef84..aac5a8cb8 100644
--- a/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs
+++ b/MediaBrowser.ServerApplication/EntryPoints/StartupWizard.cs
@@ -64,7 +64,10 @@ namespace MediaBrowser.ServerApplication.EntryPoints
{
_logger.ErrorException("Error launching startup wizard", ex);
- MessageBox.Show("There was an error launching the Media Browser startup wizard. Please ensure a web browser is installed on the machine and is configured as the default browser.", "Media Browser");
+ if (!_appHost.IsBackgroundService)
+ {
+ MessageBox.Show("There was an error launching the Media Browser startup wizard. Please ensure a web browser is installed on the machine and is configured as the default browser.", "Media Browser");
+ }
}
}
diff --git a/MediaBrowser.ServerApplication/IApplicationInterface.cs b/MediaBrowser.ServerApplication/IApplicationInterface.cs
new file mode 100644
index 000000000..e75324826
--- /dev/null
+++ b/MediaBrowser.ServerApplication/IApplicationInterface.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace MediaBrowser.ServerApplication
+{
+ /// <summary>
+ /// Interface IApplicationInterface
+ /// </summary>
+ public interface IApplicationInterface
+ {
+ /// <summary>
+ /// Gets a value indicating whether this instance is background service.
+ /// </summary>
+ /// <value><c>true</c> if this instance is background service; otherwise, <c>false</c>.</value>
+ bool IsBackgroundService { get; }
+
+ /// <summary>
+ /// Shutdowns the application.
+ /// </summary>
+ void ShutdownApplication();
+
+ /// <summary>
+ /// Restarts the application.
+ /// </summary>
+ void RestartApplication();
+
+ /// <summary>
+ /// Called when [unhandled exception].
+ /// </summary>
+ /// <param name="ex">The ex.</param>
+ void OnUnhandledException(Exception ex);
+ }
+}
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
new file mode 100644
index 000000000..e5d44c0f5
--- /dev/null
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -0,0 +1,134 @@
+using MediaBrowser.Common.Constants;
+using MediaBrowser.Common.Implementations.Updates;
+using MediaBrowser.Server.Implementations;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Windows;
+using Microsoft.Win32;
+
+namespace MediaBrowser.ServerApplication
+{
+ public class MainStartup
+ {
+ /// <summary>
+ /// The single instance mutex
+ /// </summary>
+ private static Mutex _singleInstanceMutex;
+
+ private static IApplicationInterface _applicationInterface;
+
+ /// <summary>
+ /// Defines the entry point of the application.
+ /// </summary>
+ [STAThread]
+ public static void Main()
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+
+ bool createdNew;
+
+ var runningPath = Process.GetCurrentProcess().MainModule.FileName.Replace(Path.DirectorySeparatorChar.ToString(), string.Empty);
+
+ _singleInstanceMutex = new Mutex(true, @"Local\" + runningPath, out createdNew);
+
+ if (!createdNew)
+ {
+ _singleInstanceMutex = null;
+ return;
+ }
+
+ // Look for the existence of an update archive
+ var appPaths = new ServerApplicationPaths();
+ var updateArchive = Path.Combine(appPaths.TempUpdatePath, Constants.MbServerPkgName + ".zip");
+ if (File.Exists(updateArchive))
+ {
+ // Update is there - execute update
+ try
+ {
+ new ApplicationUpdater().UpdateApplication(MBApplication.MBServer, appPaths, updateArchive);
+
+ // And just let the app exit so it can update
+ return;
+ }
+ catch (Exception e)
+ {
+ MessageBox.Show(string.Format("Error attempting to update application.\n\n{0}\n\n{1}", e.GetType().Name, e.Message));
+ }
+ }
+
+ StartApplication();
+ }
+
+ private static void StartApplication()
+ {
+ SystemEvents.SessionEnding += SystemEvents_SessionEnding;
+ var commandLineArgs = Environment.GetCommandLineArgs();
+
+ if (commandLineArgs.Length > 1 && commandLineArgs[1].Equals("-service"))
+ {
+ // Start application as a service
+ StartBackgroundService();
+ }
+ else
+ {
+ StartWpfApp();
+ }
+ }
+
+ static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
+ {
+ // Try to shutdown gracefully
+ if (_applicationInterface != null)
+ {
+ _applicationInterface.ShutdownApplication();
+ }
+ }
+
+ private static void StartWpfApp()
+ {
+ var app = new App();
+
+ _applicationInterface = app;
+
+ app.Run();
+ }
+
+ private static void StartBackgroundService()
+ {
+
+ }
+
+ static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ var exception = (Exception)e.ExceptionObject;
+
+ if (_applicationInterface != null)
+ {
+ _applicationInterface.OnUnhandledException(exception);
+ }
+
+ if (!Debugger.IsAttached)
+ {
+ Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(exception));
+ }
+ }
+
+ /// <summary>
+ /// Releases the mutex.
+ /// </summary>
+ internal static void ReleaseMutex()
+ {
+ if (_singleInstanceMutex == null)
+ {
+ return;
+ }
+
+ _singleInstanceMutex.ReleaseMutex();
+ _singleInstanceMutex.Close();
+ _singleInstanceMutex.Dispose();
+ _singleInstanceMutex = null;
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs
index 974bb6f48..4dcdeef59 100644
--- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs
+++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs
@@ -119,7 +119,7 @@ namespace MediaBrowser.ServerApplication
Dispatcher.InvokeAsync(() =>
{
- var logWindow = App.Instance.Windows.OfType<LogWindow>().FirstOrDefault();
+ var logWindow = App.Current.Windows.OfType<LogWindow>().FirstOrDefault();
if ((logWindow == null && _configurationManager.Configuration.ShowLogWindow) || (logWindow != null && !_configurationManager.Configuration.ShowLogWindow))
{
@@ -204,7 +204,7 @@ namespace MediaBrowser.ServerApplication
{
App.OpenUrl("https://github.com/MediaBrowser/MediaBrowser/wiki");
}
-
+
/// <summary>
/// Occurs when [property changed].
/// </summary>
@@ -258,7 +258,7 @@ namespace MediaBrowser.ServerApplication
{
App.OpenDashboardPage("dashboard.html", loggedInUser, _configurationManager, _appHost);
}
-
+
/// <summary>
/// Handles the click event of the cmVisitCT control.
/// </summary>
@@ -285,9 +285,9 @@ namespace MediaBrowser.ServerApplication
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
- private void cmExit_click(object sender, RoutedEventArgs e)
+ private async void cmExit_click(object sender, RoutedEventArgs e)
{
- Application.Current.Shutdown();
+ await _appHost.Shutdown().ConfigureAwait(false);
}
/// <summary>
@@ -295,9 +295,9 @@ namespace MediaBrowser.ServerApplication
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
- private void cmdReloadServer_click(object sender, RoutedEventArgs e)
+ private async void cmdReloadServer_click(object sender, RoutedEventArgs e)
{
- App.Instance.Restart();
+ await _appHost.Restart().ConfigureAwait(false);
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index bc84fca50..34d7eaf02 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -57,7 +57,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
- <StartupObject>MediaBrowser.ServerApplication.App</StartupObject>
+ <StartupObject>MediaBrowser.ServerApplication.MainStartup</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\Images\icon.ico</ApplicationIcon>
@@ -187,6 +187,7 @@
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Remoting" />
+ <Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\MahApps.Metro.0.11.0.17-ALPHA\lib\net45\System.Windows.Interactivity.dll</HintPath>
@@ -203,8 +204,13 @@
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="BackgroundService.cs">
+ <SubType>Component</SubType>
+ </Compile>
<Compile Include="EntryPoints\StartupWizard.cs" />
<Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
+ <Compile Include="IApplicationInterface.cs" />
+ <Compile Include="MainStartup.cs" />
<Compile Include="Splash\SplashWindow.xaml.cs">
<DependentUpon>SplashWindow.xaml</DependentUpon>
</Compile>