using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Common.Implementations; using MediaBrowser.Common.Implementations.ScheduledTasks; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Activity; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Connect; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.FileOrganization; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.News; using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.Sync; using MediaBrowser.Controller.Themes; using MediaBrowser.Controller.TV; using MediaBrowser.Dlna; using MediaBrowser.Dlna.ConnectionManager; using MediaBrowser.Dlna.ContentDirectory; using MediaBrowser.Dlna.Main; using MediaBrowser.LocalMetadata.Providers; using MediaBrowser.MediaEncoding.BdInfo; using MediaBrowser.MediaEncoding.Encoder; using MediaBrowser.MediaEncoding.Subtitles; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Chapters; using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Subtitles; using MediaBrowser.Server.Implementations; using MediaBrowser.Server.Implementations.Activity; using MediaBrowser.Server.Implementations.Channels; using MediaBrowser.Server.Implementations.Collections; using MediaBrowser.Server.Implementations.Configuration; using MediaBrowser.Server.Implementations.Connect; using MediaBrowser.Server.Implementations.Drawing; using MediaBrowser.Server.Implementations.Dto; using MediaBrowser.Server.Implementations.EntryPoints; using MediaBrowser.Server.Implementations.FileOrganization; using MediaBrowser.Server.Implementations.HttpServer; using MediaBrowser.Server.Implementations.HttpServer.Security; using MediaBrowser.Server.Implementations.IO; using MediaBrowser.Server.Implementations.Library; using MediaBrowser.Server.Implementations.LiveTv; using MediaBrowser.Server.Implementations.Localization; using MediaBrowser.Server.Implementations.MediaEncoder; using MediaBrowser.Server.Implementations.Notifications; using MediaBrowser.Server.Implementations.Persistence; using MediaBrowser.Server.Implementations.Playlists; using MediaBrowser.Server.Implementations.Security; using MediaBrowser.Server.Implementations.ServerManager; using MediaBrowser.Server.Implementations.Session; using MediaBrowser.Server.Implementations.Sync; using MediaBrowser.Server.Implementations.Themes; using MediaBrowser.Server.Implementations.TV; using MediaBrowser.ServerApplication.FFMpeg; using MediaBrowser.ServerApplication.IO; using MediaBrowser.ServerApplication.Native; using MediaBrowser.ServerApplication.Networking; using MediaBrowser.WebDashboard.Api; using MediaBrowser.XbmcMetadata.Providers; using System; using System.Collections.Generic; using System.Globalization; 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 : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost { /// <summary> /// Gets the server configuration manager. /// </summary> /// <value>The server configuration manager.</value> public IServerConfigurationManager ServerConfigurationManager { get { return (IServerConfigurationManager)ConfigurationManager; } } /// <summary> /// Gets the name of the web application that can be used for url building. /// All api urls will be of the form {protocol}://{host}:{port}/{appname}/... /// </summary> /// <value>The name of the web application.</value> public string WebApplicationName { get { return "mediabrowser"; } } /// <summary> /// Gets the HTTP server URL prefix. /// </summary> /// <value>The HTTP server URL prefix.</value> private IEnumerable<string> HttpServerUrlPrefixes { get { var list = new List<string> { "http://+:" + ServerConfigurationManager.Configuration.HttpServerPortNumber + "/" + WebApplicationName + "/" }; return list; } } /// <summary> /// Gets the configuration manager. /// </summary> /// <returns>IConfigurationManager.</returns> protected override IConfigurationManager GetConfigurationManager() { return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer); } /// <summary> /// Gets or sets the server manager. /// </summary> /// <value>The server manager.</value> private IServerManager ServerManager { get; set; } /// <summary> /// Gets or sets the user manager. /// </summary> /// <value>The user manager.</value> public IUserManager UserManager { get; set; } /// <summary> /// Gets or sets the library manager. /// </summary> /// <value>The library manager.</value> internal ILibraryManager LibraryManager { get; set; } /// <summary> /// Gets or sets the directory watchers. /// </summary> /// <value>The directory watchers.</value> private ILibraryMonitor LibraryMonitor { get; set; } /// <summary> /// Gets or sets the provider manager. /// </summary> /// <value>The provider manager.</value> private IProviderManager ProviderManager { get; set; } /// <summary> /// Gets or sets the HTTP server. /// </summary> /// <value>The HTTP server.</value> private IHttpServer HttpServer { get; set; } private IDtoService DtoService { get; set; } private IImageProcessor ImageProcessor { get; set; } private ISeriesOrderManager SeriesOrderManager { get; set; } /// <summary> /// Gets or sets the media encoder. /// </summary> /// <value>The media encoder.</value> private IMediaEncoder MediaEncoder { get; set; } private IConnectManager ConnectManager { get; set; } private ISessionManager SessionManager { get; set; } private ILiveTvManager LiveTvManager { get; set; } internal ILocalizationManager LocalizationManager { get; set; } private IEncodingManager EncodingManager { get; set; } private IChannelManager ChannelManager { get; set; } private ISyncManager SyncManager { get; set; } /// <summary> /// Gets or sets the user data repository. /// </summary> /// <value>The user data repository.</value> private IUserDataManager UserDataManager { get; set; } private IUserRepository UserRepository { get; set; } internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; } internal IItemRepository ItemRepository { get; set; } private INotificationsRepository NotificationsRepository { get; set; } private IFileOrganizationRepository FileOrganizationRepository { get; set; } private IProviderRepository ProviderRepository { get; set; } private INotificationManager NotificationManager { get; set; } private ISubtitleManager SubtitleManager { get; set; } private IChapterManager ChapterManager { get; set; } internal IUserViewManager UserViewManager { get; set; } private IAuthenticationRepository AuthenticationRepository { get; set; } private ISyncRepository SyncRepository { get; set; } private ITVSeriesManager TVSeriesManager { get; set; } private StartupOptions _startupOptions; /// <summary> /// Initializes a new instance of the <see cref="ApplicationHost" /> class. /// </summary> /// <param name="applicationPaths">The application paths.</param> /// <param name="logManager">The log manager.</param> /// <param name="supportsRunningAsService">if set to <c>true</c> [supports running as service].</param> /// <param name="isRunningAsService">if set to <c>true</c> [is running as service].</param> /// <param name="options">The options.</param> public ApplicationHost(ServerApplicationPaths applicationPaths, ILogManager logManager, bool supportsRunningAsService, bool isRunningAsService, StartupOptions options) : base(applicationPaths, logManager) { _startupOptions = options; _isRunningAsService = isRunningAsService; SupportsRunningAsService = supportsRunningAsService; } private readonly bool _isRunningAsService; public override bool IsRunningAsService { get { return _isRunningAsService; } } public bool SupportsRunningAsService { get; private set; } /// <summary> /// Gets the name. /// </summary> /// <value>The name.</value> public override string Name { get { return "Media Browser Server"; } } /// <summary> /// Gets a value indicating whether this instance can self restart. /// </summary> /// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value> public override bool CanSelfRestart { get { return NativeApp.CanSelfRestart; } } public bool SupportsAutoRunAtStartup { get { return NativeApp.SupportsAutoRunAtStartup; } } /// <summary> /// Runs the startup tasks. /// </summary> /// <returns>Task.</returns> public override async Task RunStartupTasks() { await base.RunStartupTasks().ConfigureAwait(false); Logger.Info("Core startup complete"); Parallel.ForEach(GetExports<IServerEntryPoint>(), entryPoint => { try { entryPoint.Run(); } catch (Exception ex) { Logger.ErrorException("Error in {0}", ex, entryPoint.GetType().Name); } }); LogManager.RemoveConsoleOutput(); } public override async Task Init(IProgress<double> progress) { PerformVersionMigration(); await base.Init(progress).ConfigureAwait(false); MigrateModularConfigurations(); } private void PerformVersionMigration() { DeleteDeprecatedModules(); } private void MigrateModularConfigurations() { var saveConfig = false; if (saveConfig) { ServerConfigurationManager.SaveConfiguration(); } } private void DeleteDeprecatedModules() { try { MigrateUserFolders(); } catch (IOException) { } try { File.Delete(Path.Combine(ApplicationPaths.PluginsPath, "MBPhoto.dll")); } catch (IOException) { // Not there, no big deal } try { File.Delete(Path.Combine(ApplicationPaths.PluginsPath, "MediaBrowser.Plugins.XbmcMetadata.dll")); } catch (IOException) { // Not there, no big deal } } private void MigrateUserFolders() { var rootPath = ApplicationPaths.RootFolderPath; var folders = new DirectoryInfo(rootPath).EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Where(i => !string.Equals(i.Name, "default", StringComparison.OrdinalIgnoreCase)) .ToList(); foreach (var folder in folders) { Directory.Delete(folder.FullName, true); } } /// <summary> /// Registers resources that classes will depend on /// </summary> /// <returns>Task.</returns> protected override async Task RegisterResources(IProgress<double> progress) { await base.RegisterResources(progress).ConfigureAwait(false); RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer)); RegisterSingleInstance<IServerApplicationHost>(this); RegisterSingleInstance<IServerApplicationPaths>(ApplicationPaths); RegisterSingleInstance(ServerConfigurationManager); LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer); RegisterSingleInstance(LocalizationManager); RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer()); UserDataManager = new UserDataManager(LogManager); RegisterSingleInstance(UserDataManager); UserRepository = await GetUserRepository().ConfigureAwait(false); RegisterSingleInstance(UserRepository); DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager); RegisterSingleInstance(DisplayPreferencesRepository); ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager); RegisterSingleInstance(ItemRepository); ProviderRepository = new SqliteProviderInfoRepository(ApplicationPaths, LogManager); RegisterSingleInstance(ProviderRepository); FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false); RegisterSingleInstance(FileOrganizationRepository); AuthenticationRepository = await GetAuthenticationRepository().ConfigureAwait(false); RegisterSingleInstance(AuthenticationRepository); //SyncRepository = await GetSyncRepository().ConfigureAwait(false); //RegisterSingleInstance(SyncRepository); UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService); RegisterSingleInstance(UserManager); LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager); RegisterSingleInstance(LibraryManager); var musicManager = new MusicManager(LibraryManager); RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager)); LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(LibraryMonitor); ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager); RegisterSingleInstance(ProviderManager); SeriesOrderManager = new SeriesOrderManager(); RegisterSingleInstance(SeriesOrderManager); RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager)); HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", WebApplicationName, "dashboard/index.html"); RegisterSingleInstance(HttpServer, false); progress.Report(10); ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager); RegisterSingleInstance(ServerManager); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15)); await RegisterMediaEncoder(innerProgress).ConfigureAwait(false); progress.Report(90); ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, MediaEncoder); RegisterSingleInstance(ImageProcessor); SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager")); RegisterSingleInstance(SyncManager); DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager); RegisterSingleInstance(DtoService); var encryptionManager = new EncryptionManager(); RegisterSingleInstance<IEncryptionManager>(encryptionManager); ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager); RegisterSingleInstance(ConnectManager); SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository); RegisterSingleInstance(SessionManager); var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); RegisterSingleInstance<INewsService>(newsService); var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, LogManager.GetLogger("FileOrganizationService"), LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager); RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService); progress.Report(15); ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, Logger, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager); RegisterSingleInstance(ChannelManager); TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager); RegisterSingleInstance(TVSeriesManager); var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger); RegisterSingleInstance<IAppThemeManager>(appThemeManager); var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer); RegisterSingleInstance<IDlnaManager>(dlnaManager); var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient); RegisterSingleInstance<IConnectionManager>(connectionManager); var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager")); RegisterSingleInstance<ICollectionManager>(collectionManager); var playlistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager); RegisterSingleInstance<IPlaylistManager>(playlistManager); LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer); RegisterSingleInstance(LiveTvManager); UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager, ApplicationPaths, playlistManager); RegisterSingleInstance(UserViewManager); var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient); RegisterSingleInstance<IContentDirectory>(contentDirectory); NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager); RegisterSingleInstance(NotificationManager); SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, ItemRepository); RegisterSingleInstance(SubtitleManager); ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository); RegisterSingleInstance(ChapterManager); EncodingManager = new EncodingManager(ServerConfigurationManager, FileSystemManager, Logger, MediaEncoder, ChapterManager); RegisterSingleInstance(EncodingManager); var activityLogRepo = await GetActivityLogRepository().ConfigureAwait(false); RegisterSingleInstance(activityLogRepo); RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo)); var authContext = new AuthorizationContext(); RegisterSingleInstance<IAuthorizationContext>(authContext); RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager)); RegisterSingleInstance<IAuthService>(new AuthService(UserManager, SessionManager, authContext, ServerConfigurationManager)); RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer)); var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false)); var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false)); var userdataTask = Task.Run(async () => await ConfigureUserDataRepositories().ConfigureAwait(false)); await ConfigureNotificationsRepository().ConfigureAwait(false); progress.Report(92); await Task.WhenAll(itemsTask, displayPreferencesTask, userdataTask).ConfigureAwait(false); progress.Report(100); SetStaticProperties(); await ((UserManager)UserManager).Initialize().ConfigureAwait(false); SetKernelProperties(); } protected override INetworkManager CreateNetworkManager(ILogger logger) { return new NetworkManager(logger); } protected override IFileSystem CreateFileSystemManager() { return FileSystemFactory.CreateFileSystemManager(LogManager); } /// <summary> /// Registers the media encoder. /// </summary> /// <returns>Task.</returns> private async Task RegisterMediaEncoder(IProgress<double> progress) { var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager).GetFFMpegInfo(_startupOptions, progress).ConfigureAwait(false); MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), JsonSerializer, info.EncoderPath, info.ProbePath, info.Version); RegisterSingleInstance(MediaEncoder); } /// <summary> /// Sets the kernel properties. /// </summary> private void SetKernelProperties() { LocalizedStrings.StringFiles = GetExports<LocalizedStringData>(); } /// <summary> /// Gets the user repository. /// </summary> /// <returns>Task{IUserRepository}.</returns> private async Task<IUserRepository> GetUserRepository() { var repo = new SqliteUserRepository(JsonSerializer, LogManager, ApplicationPaths); await repo.Initialize().ConfigureAwait(false); return repo; } /// <summary> /// Gets the file organization repository. /// </summary> /// <returns>Task{IUserRepository}.</returns> private async Task<IFileOrganizationRepository> GetFileOrganizationRepository() { var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths); await repo.Initialize().ConfigureAwait(false); return repo; } private async Task<IAuthenticationRepository> GetAuthenticationRepository() { var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths); await repo.Initialize().ConfigureAwait(false); return repo; } private async Task<IActivityRepository> GetActivityLogRepository() { var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths); await repo.Initialize().ConfigureAwait(false); return repo; } private async Task<ISyncRepository> GetSyncRepository() { var repo = new SyncRepository(LogManager.GetLogger("SyncRepository"), ServerConfigurationManager.ApplicationPaths); await repo.Initialize().ConfigureAwait(false); return repo; } /// <summary> /// Configures the repositories. /// </summary> /// <returns>Task.</returns> private async Task ConfigureNotificationsRepository() { var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths); await repo.Initialize().ConfigureAwait(false); NotificationsRepository = repo; RegisterSingleInstance(NotificationsRepository); } /// <summary> /// Configures the repositories. /// </summary> /// <returns>Task.</returns> private async Task ConfigureDisplayPreferencesRepositories() { await DisplayPreferencesRepository.Initialize().ConfigureAwait(false); } /// <summary> /// Configures the item repositories. /// </summary> /// <returns>Task.</returns> private async Task ConfigureItemRepositories() { await ItemRepository.Initialize().ConfigureAwait(false); await ProviderRepository.Initialize().ConfigureAwait(false); ((LibraryManager)LibraryManager).ItemRepository = ItemRepository; } /// <summary> /// Configures the user data repositories. /// </summary> /// <returns>Task.</returns> private async Task ConfigureUserDataRepositories() { var repo = new SqliteUserDataRepository(ApplicationPaths, LogManager); await repo.Initialize().ConfigureAwait(false); ((UserDataManager)UserDataManager).Repository = repo; } /// <summary> /// Dirty hacks /// </summary> private void SetStaticProperties() { // For now there's no real way to inject these properly BaseItem.Logger = LogManager.GetLogger("BaseItem"); BaseItem.ConfigurationManager = ServerConfigurationManager; BaseItem.LibraryManager = LibraryManager; BaseItem.ProviderManager = ProviderManager; BaseItem.LocalizationManager = LocalizationManager; BaseItem.ItemRepository = ItemRepository; User.XmlSerializer = XmlSerializer; User.UserManager = UserManager; LocalizedStrings.ApplicationPaths = ApplicationPaths; Folder.UserManager = UserManager; BaseItem.FileSystem = FileSystemManager; BaseItem.UserDataManager = UserDataManager; BaseItem.ChannelManager = ChannelManager; BaseItem.LiveTvManager = LiveTvManager; Folder.UserViewManager = UserViewManager; UserView.TVSeriesManager = TVSeriesManager; } /// <summary> /// Finds the parts. /// </summary> protected override void FindParts() { if (IsFirstRun) { RegisterServerWithAdministratorAccess(); } base.FindParts(); HttpServer.Init(GetExports<IRestfulService>(false)); ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false)); StartServer(true); LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), GetExports<IVirtualFolderCreator>(), GetExports<IItemResolver>(), GetExports<IIntroProvider>(), GetExports<IBaseItemComparer>(), GetExports<ILibraryPostScanTask>()); ProviderManager.AddParts(GetExports<IImageProvider>(), GetExports<IMetadataService>(), GetExports<IItemIdentityProvider>(), GetExports<IItemIdentityConverter>(), GetExports<IMetadataProvider>(), GetExports<IMetadataSaver>(), GetExports<IImageSaver>(), GetExports<IExternalId>()); SeriesOrderManager.AddParts(GetExports<ISeriesOrderProvider>()); ImageProcessor.AddParts(GetExports<IImageEnhancer>()); LiveTvManager.AddParts(GetExports<ILiveTvService>()); SubtitleManager.AddParts(GetExports<ISubtitleProvider>()); ChapterManager.AddParts(GetExports<IChapterProvider>()); SessionManager.AddParts(GetExports<ISessionControllerFactory>()); ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>()); NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>()); SyncManager.AddParts(GetExports<ISyncProvider>()); } /// <summary> /// Starts the server. /// </summary> /// <param name="retryOnFailure">if set to <c>true</c> [retry on failure].</param> private void StartServer(bool retryOnFailure) { try { ServerManager.Start(HttpServerUrlPrefixes); } catch (Exception ex) { Logger.ErrorException("Error starting http server", ex); if (retryOnFailure) { RegisterServerWithAdministratorAccess(); StartServer(false); } else { throw; } } } /// <summary> /// Called when [configuration updated]. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected override void OnConfigurationUpdated(object sender, EventArgs e) { base.OnConfigurationUpdated(sender, e); if (!HttpServer.UrlPrefixes.SequenceEqual(HttpServerUrlPrefixes, StringComparer.OrdinalIgnoreCase)) { NotifyPendingRestart(); } } /// <summary> /// Restarts this instance. /// </summary> public override async Task Restart() { if (!CanSelfRestart) { throw new InvalidOperationException("The server is unable to self-restart. Please restart manually."); } try { await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { Logger.ErrorException("Error sending server restart notification", ex); } Logger.Debug("Calling NativeApp.Restart"); NativeApp.Restart(); } /// <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 override bool CanSelfUpdate { get { #if DEBUG return false; #endif #pragma warning disable 162 return NativeApp.CanSelfUpdate; #pragma warning restore 162 } } /// <summary> /// Gets the composable part assemblies. /// </summary> /// <returns>IEnumerable{Assembly}.</returns> protected override IEnumerable<Assembly> GetComposablePartAssemblies() { var list = GetPluginAssemblies() .ToList(); // 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 // Include composable parts in the Api assembly list.Add(typeof(ApiEntryPoint).Assembly); // Include composable parts in the Dashboard assembly list.Add(typeof(DashboardService).Assembly); // Include composable parts in the Model assembly list.Add(typeof(SystemInfo).Assembly); // Include composable parts in the Common assembly list.Add(typeof(IApplicationHost).Assembly); // Include composable parts in the Controller assembly list.Add(typeof(IServerApplicationHost).Assembly); // Include composable parts in the Providers assembly list.Add(typeof(ProviderUtils).Assembly); // Common implementations list.Add(typeof(TaskManager).Assembly); // Server implementations list.Add(typeof(ServerApplicationPaths).Assembly); // MediaEncoding list.Add(typeof(MediaEncoder).Assembly); // Dlna list.Add(typeof(DlnaEntryPoint).Assembly); // Local metadata list.Add(typeof(AlbumXmlProvider).Assembly); // Xbmc list.Add(typeof(ArtistNfoProvider).Assembly); list.AddRange(Assemblies.GetAssembliesWithParts()); // Include composable parts in the running assembly list.Add(GetType().Assembly); return list; } /// <summary> /// Gets the plugin assemblies. /// </summary> /// <returns>IEnumerable{Assembly}.</returns> private IEnumerable<Assembly> GetPluginAssemblies() { try { return Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) .Select(LoadAssembly) .Where(a => a != null) .ToList(); } catch (DirectoryNotFoundException) { return new List<Assembly>(); } } /// <summary> /// Gets the system status. /// </summary> /// <returns>SystemInfo.</returns> public virtual SystemInfo GetSystemInfo() { return new SystemInfo { HasPendingRestart = HasPendingRestart, Version = ApplicationVersion.ToString(), IsNetworkDeployed = CanSelfUpdate, WebSocketPortNumber = HttpServerPort, SupportsNativeWebSocket = true, FailedPluginAssemblies = FailedAssemblies.ToList(), InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToList(), CompletedInstallations = InstallationManager.CompletedInstallations.ToList(), Id = SystemId, ProgramDataPath = ApplicationPaths.ProgramDataPath, LogPath = ApplicationPaths.LogDirectoryPath, ItemsByNamePath = ApplicationPaths.ItemsByNamePath, InternalMetadataPath = ApplicationPaths.InternalMetadataPath, CachePath = ApplicationPaths.CachePath, MacAddress = GetMacAddress(), HttpServerPortNumber = HttpServerPort, OperatingSystem = Environment.OSVersion.ToString(), CanSelfRestart = CanSelfRestart, CanSelfUpdate = CanSelfUpdate, WanAddress = ConnectManager.WanApiAddress, HasUpdateAvailable = HasUpdateAvailable, SupportsAutoRunAtStartup = SupportsAutoRunAtStartup, TranscodingTempPath = ApplicationPaths.TranscodingTempPath, IsRunningAsService = IsRunningAsService, SupportsRunningAsService = SupportsRunningAsService, ServerName = FriendlyName, LocalAddress = GetLocalIpAddress() }; } /// <summary> /// Gets the local ip address. /// </summary> /// <returns>System.String.</returns> private string GetLocalIpAddress() { // Return the first matched address, if found, or the first known local address var address = HttpServerIpAddresses.FirstOrDefault(); if (!string.IsNullOrWhiteSpace(address)) { address = string.Format("http://{0}:{1}", address, ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(CultureInfo.InvariantCulture)); } return address; } public IEnumerable<string> HttpServerIpAddresses { get { var localAddresses = NetworkManager.GetLocalIpAddresses() .ToList(); if (localAddresses.Count < 2) { return localAddresses; } var httpServerAddresses = HttpServer.LocalEndPoints .Select(i => i.Split(':').FirstOrDefault()) .Where(i => !string.IsNullOrEmpty(i)) .ToList(); // Cross-check the local ip addresses with addresses that have been received on with the http server var matchedAddresses = httpServerAddresses .Where(i => localAddresses.Contains(i, StringComparer.OrdinalIgnoreCase)) .ToList(); if (matchedAddresses.Count == 0) { return localAddresses.Take(1); } return matchedAddresses; } } public string FriendlyName { get { return string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.ServerName) ? Environment.MachineName : ServerConfigurationManager.Configuration.ServerName; } } public int HttpServerPort { get { return ServerConfigurationManager.Configuration.HttpServerPortNumber; } } /// <summary> /// Gets the mac address. /// </summary> /// <returns>System.String.</returns> private string GetMacAddress() { try { return NetworkManager.GetMacAddress(); } catch (Exception ex) { Logger.ErrorException("Error getting mac address", ex); return null; } } /// <summary> /// Shuts down. /// </summary> public override async Task Shutdown() { try { await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { Logger.ErrorException("Error sending server shutdown notification", ex); } NativeApp.Shutdown(); } /// <summary> /// Registers the server with administrator access. /// </summary> private void RegisterServerWithAdministratorAccess() { Logger.Info("Requesting administrative access to authorize http server"); try { ServerAuthorization.AuthorizeServer( ServerConfigurationManager.Configuration.HttpServerPortNumber, HttpServerUrlPrefixes.First(), UdpServerEntryPoint.PortNumber, ConfigurationManager.CommonApplicationPaths.TempDirectory); } catch (Exception ex) { Logger.ErrorException("Error authorizing server", ex); } } public event EventHandler HasUpdateAvailableChanged; private bool _hasUpdateAvailable; public bool HasUpdateAvailable { get { return _hasUpdateAvailable; } set { var fireEvent = value && !_hasUpdateAvailable; _hasUpdateAvailable = value; if (fireEvent) { EventHelper.FireEventIfNotNull(HasUpdateAvailableChanged, this, EventArgs.Empty, Logger); } } } /// <summary> /// Checks for update. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task{CheckForUpdateResult}.</returns> public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress) { var result = await NativeApp.CheckForApplicationUpdate(ApplicationVersion, ConfigurationManager.CommonConfiguration.SystemUpdateLevel, InstallationManager, cancellationToken, progress).ConfigureAwait(false); HasUpdateAvailable = result.IsUpdateAvailable; if (result.IsUpdateAvailable) { Logger.Info("New application version is available: {0}", result.AvailableVersion); } return result; } /// <summary> /// Updates the application. /// </summary> /// <param name="package">The package that contains the update</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress) { await InstallationManager.InstallPackage(package, progress, cancellationToken).ConfigureAwait(false); HasUpdateAvailable = false; OnApplicationUpdated(package); } /// <summary> /// Configures the automatic run at startup. /// </summary> /// <param name="autorun">if set to <c>true</c> [autorun].</param> protected override void ConfigureAutoRunAtStartup(bool autorun) { if (SupportsAutoRunAtStartup) { Autorun.Configure(autorun); } } } }