aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Core/ApplicationHost.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Core/ApplicationHost.cs')
-rw-r--r--Emby.Server.Core/ApplicationHost.cs1629
1 files changed, 1629 insertions, 0 deletions
diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs
new file mode 100644
index 000000000..9e0aee325
--- /dev/null
+++ b/Emby.Server.Core/ApplicationHost.cs
@@ -0,0 +1,1629 @@
+using MediaBrowser.Api;
+using MediaBrowser.Common;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Extensions;
+using Emby.Common.Implementations.ScheduledTasks;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Progress;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Chapters;
+using MediaBrowser.Controller.Collections;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Connect;
+using MediaBrowser.Controller.Devices;
+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.MediaEncoding;
+using MediaBrowser.Controller.Net;
+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.TV;
+using MediaBrowser.LocalMetadata.Savers;
+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.WebDashboard.Api;
+using MediaBrowser.XbmcMetadata.Providers;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.Common.Implementations;
+using Emby.Common.Implementations.Archiving;
+using Emby.Common.Implementations.Networking;
+using Emby.Common.Implementations.Reflection;
+using Emby.Common.Implementations.Serialization;
+using Emby.Common.Implementations.TextEncoding;
+using Emby.Common.Implementations.Updates;
+using Emby.Common.Implementations.Xml;
+using Emby.Photos;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Api.Playback;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Common.Security;
+using MediaBrowser.Common.Updates;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using Emby.Dlna;
+using Emby.Dlna.ConnectionManager;
+using Emby.Dlna.ContentDirectory;
+using Emby.Dlna.Main;
+using Emby.Dlna.MediaReceiverRegistrar;
+using Emby.Dlna.Ssdp;
+using Emby.Server.Core;
+using Emby.Server.Core.Activity;
+using Emby.Server.Core.Configuration;
+using Emby.Server.Core.Data;
+using Emby.Server.Core.Devices;
+using Emby.Server.Core.FFMpeg;
+using Emby.Server.Core.IO;
+using Emby.Server.Core.Localization;
+using Emby.Server.Core.Migrations;
+using Emby.Server.Core.Notifications;
+using Emby.Server.Core.Security;
+using Emby.Server.Core.Social;
+using Emby.Server.Core.Sync;
+using Emby.Server.Implementations.Activity;
+using Emby.Server.Implementations.Channels;
+using Emby.Server.Implementations.Collections;
+using Emby.Server.Implementations.Connect;
+using Emby.Server.Implementations.Devices;
+using Emby.Server.Implementations.Dto;
+using Emby.Server.Implementations.EntryPoints;
+using Emby.Server.Implementations.FileOrganization;
+using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.HttpServer.Security;
+using Emby.Server.Implementations.Library;
+using Emby.Server.Implementations.LiveTv;
+using Emby.Server.Implementations.Localization;
+using Emby.Server.Implementations.MediaEncoder;
+using Emby.Server.Implementations.Notifications;
+using Emby.Server.Implementations.Persistence;
+using Emby.Server.Implementations.Playlists;
+using Emby.Server.Implementations.Security;
+using Emby.Server.Implementations.ServerManager;
+using Emby.Server.Implementations.Session;
+using Emby.Server.Implementations.Social;
+using Emby.Server.Implementations.Sync;
+using Emby.Server.Implementations.TV;
+using Emby.Server.Implementations.Updates;
+using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.News;
+using MediaBrowser.Model.Reflection;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Social;
+using MediaBrowser.Model.Text;
+using MediaBrowser.Model.Xml;
+using OpenSubtitlesHandler;
+using ServiceStack;
+using SocketHttpListener.Primitives;
+using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
+using Emby.Drawing;
+
+namespace Emby.Server.Core
+{
+ /// <summary>
+ /// Class CompositionRoot
+ /// </summary>
+ public class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost, IDependencyContainer
+ {
+ /// <summary>
+ /// Gets the server configuration manager.
+ /// </summary>
+ /// <value>The server configuration manager.</value>
+ public IServerConfigurationManager ServerConfigurationManager
+ {
+ get { return (IServerConfigurationManager)ConfigurationManager; }
+ }
+
+ /// <summary>
+ /// Gets the configuration manager.
+ /// </summary>
+ /// <returns>IConfigurationManager.</returns>
+ protected override IConfigurationManager GetConfigurationManager()
+ {
+ return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer, FileSystemManager);
+ }
+
+ /// <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; }
+
+ /// <summary>
+ /// Gets or sets the media encoder.
+ /// </summary>
+ /// <value>The media encoder.</value>
+ private IMediaEncoder MediaEncoder { get; set; }
+ private ISubtitleEncoder SubtitleEncoder { get; set; }
+
+ private IConnectManager ConnectManager { get; set; }
+ private ISessionManager SessionManager { get; set; }
+
+ private ILiveTvManager LiveTvManager { get; set; }
+
+ public 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 INotificationManager NotificationManager { get; set; }
+ private ISubtitleManager SubtitleManager { get; set; }
+ private IChapterManager ChapterManager { get; set; }
+ private IDeviceManager DeviceManager { get; set; }
+
+ internal IUserViewManager UserViewManager { get; set; }
+
+ private IAuthenticationRepository AuthenticationRepository { get; set; }
+ private ISyncRepository SyncRepository { get; set; }
+ private ITVSeriesManager TVSeriesManager { get; set; }
+ private ICollectionManager CollectionManager { get; set; }
+ private IMediaSourceManager MediaSourceManager { get; set; }
+ private IPlaylistManager PlaylistManager { get; set; }
+
+ /// <summary>
+ /// Gets or sets the installation manager.
+ /// </summary>
+ /// <value>The installation manager.</value>
+ protected IInstallationManager InstallationManager { get; private set; }
+ /// <summary>
+ /// Gets the security manager.
+ /// </summary>
+ /// <value>The security manager.</value>
+ protected ISecurityManager SecurityManager { get; private set; }
+
+ /// <summary>
+ /// Gets or sets the zip client.
+ /// </summary>
+ /// <value>The zip client.</value>
+ protected IZipClient ZipClient { get; private set; }
+
+ protected IAuthService AuthService { get; private set; }
+
+ private readonly StartupOptions _startupOptions;
+ private readonly string _releaseAssetFilename;
+
+ internal INativeApp NativeApp { get; set; }
+
+ internal IPowerManagement PowerManagement { get; private set; }
+ internal IImageEncoder ImageEncoder { get; private set; }
+
+ private readonly Action<string, string> _certificateGenerator;
+ private readonly Func<string> _defaultUserNameFactory;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
+ /// </summary>
+ public ApplicationHost(ServerApplicationPaths applicationPaths,
+ ILogManager logManager,
+ StartupOptions options,
+ IFileSystem fileSystem,
+ INativeApp nativeApp,
+ IPowerManagement powerManagement,
+ string releaseAssetFilename,
+ IEnvironmentInfo environmentInfo,
+ IImageEncoder imageEncoder,
+ ISystemEvents systemEvents,
+ IMemoryStreamFactory memoryStreamFactory,
+ INetworkManager networkManager,
+ Action<string, string> certificateGenerator,
+ Func<string> defaultUsernameFactory)
+ : base(applicationPaths,
+ logManager,
+ fileSystem,
+ environmentInfo,
+ systemEvents,
+ memoryStreamFactory,
+ networkManager)
+ {
+ _startupOptions = options;
+ _certificateGenerator = certificateGenerator;
+ _releaseAssetFilename = releaseAssetFilename;
+ _defaultUserNameFactory = defaultUsernameFactory;
+ NativeApp = nativeApp;
+ PowerManagement = powerManagement;
+
+ ImageEncoder = imageEncoder;
+
+ SetBaseExceptionMessage();
+ }
+
+ private Version _version;
+ /// <summary>
+ /// Gets the current application version
+ /// </summary>
+ /// <value>The application version.</value>
+ public override Version ApplicationVersion
+ {
+ get
+ {
+ return _version ?? (_version = GetAssembly(NativeApp.GetType()).GetName().Version);
+ }
+ }
+
+ public override bool IsRunningAsService
+ {
+ get { return NativeApp.IsRunningAsService; }
+ }
+
+ public bool SupportsRunningAsService
+ {
+ get { return NativeApp.SupportsRunningAsService; }
+ }
+
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public override string Name
+ {
+ get
+ {
+ return "Emby Server";
+ }
+ }
+
+ private Assembly GetAssembly(Type type)
+ {
+ return type.GetTypeInfo().Assembly;
+ }
+
+ /// <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; }
+ }
+
+ private void SetBaseExceptionMessage()
+ {
+ var builder = GetBaseExceptionMessage(ApplicationPaths);
+
+ // Skip if plugins haven't been loaded yet
+ //if (Plugins != null)
+ //{
+ // var pluginString = string.Join("|", Plugins.Select(i => i.Name + "-" + i.Version.ToString()).ToArray());
+ // builder.Insert(0, string.Format("Plugins: {0}{1}", pluginString, Environment.NewLine));
+ //}
+
+ builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
+ builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
+
+ LogManager.ExceptionMessagePrefix = builder.ToString();
+ }
+
+ /// <summary>
+ /// Runs the startup tasks.
+ /// </summary>
+ public override async Task RunStartupTasks()
+ {
+ await PerformPreInitMigrations().ConfigureAwait(false);
+
+ if (ServerConfigurationManager.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion &&
+ ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
+ {
+ TaskManager.SuspendTriggers = true;
+ }
+
+ await base.RunStartupTasks().ConfigureAwait(false);
+
+ await MediaEncoder.Init().ConfigureAwait(false);
+
+ if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath))
+ {
+ if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
+ {
+ ServerConfigurationManager.Configuration.IsStartupWizardCompleted = false;
+ ServerConfigurationManager.SaveConfiguration();
+ }
+ }
+
+ Logger.Info("ServerId: {0}", SystemId);
+ Logger.Info("Core startup complete");
+ HttpServer.GlobalResponse = null;
+
+ PerformPostInitMigrations();
+ Logger.Info("Post-init migrations complete");
+
+ foreach (var entryPoint in GetExports<IServerEntryPoint>().ToList())
+ {
+ var name = entryPoint.GetType().FullName;
+ Logger.Info("Starting entry point {0}", name);
+ var now = DateTime.UtcNow;
+ try
+ {
+ entryPoint.Run();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error in {0}", ex, name);
+ }
+ Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
+ }
+ Logger.Info("All entry points have started");
+
+ LogManager.RemoveConsoleOutput();
+ }
+
+ protected override IJsonSerializer CreateJsonSerializer()
+ {
+ try
+ {
+ // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4
+ Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0=");
+ }
+ catch
+ {
+ // Failing under mono
+ }
+
+ var result = new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
+
+ ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "PlaceOfBirth", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+ ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "ShortOverview", "Taglines", "Keywords", "ExtraType" };
+
+ return result;
+ }
+
+ public override Task Init(IProgress<double> progress)
+ {
+ HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
+ HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
+
+ // Safeguard against invalid configuration
+ if (HttpPort == HttpsPort)
+ {
+ HttpPort = ServerConfiguration.DefaultHttpPort;
+ HttpsPort = ServerConfiguration.DefaultHttpsPort;
+ }
+
+ return base.Init(progress);
+ }
+
+ private async Task PerformPreInitMigrations()
+ {
+ var migrations = new List<IVersionMigration>
+ {
+ new UpdateLevelMigration(ServerConfigurationManager, this, HttpClient, JsonSerializer, _releaseAssetFilename, Logger)
+ };
+
+ foreach (var task in migrations)
+ {
+ try
+ {
+ await task.Run().ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error running migration", ex);
+ }
+ }
+ }
+
+ private void PerformPostInitMigrations()
+ {
+ var migrations = new List<IVersionMigration>
+ {
+ new DbMigration(ServerConfigurationManager, TaskManager)
+ };
+
+ foreach (var task in migrations)
+ {
+ try
+ {
+ task.Run();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error running migration", ex);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Registers resources that classes will depend on
+ /// </summary>
+ protected override async Task RegisterResources(IProgress<double> progress)
+ {
+ await base.RegisterResources(progress).ConfigureAwait(false);
+
+ RegisterSingleInstance(PowerManagement);
+
+ SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider);
+ RegisterSingleInstance(SecurityManager);
+
+ InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider);
+ RegisterSingleInstance(InstallationManager);
+
+ ZipClient = new ZipClient(FileSystemManager);
+ RegisterSingleInstance(ZipClient);
+
+ RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer, XmlSerializer));
+
+ RegisterSingleInstance<IServerApplicationHost>(this);
+ RegisterSingleInstance<IServerApplicationPaths>(ApplicationPaths);
+
+ RegisterSingleInstance(ServerConfigurationManager);
+
+ IAssemblyInfo assemblyInfo = new AssemblyInfo();
+ RegisterSingleInstance<IAssemblyInfo>(assemblyInfo);
+
+ LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LogManager.GetLogger("LocalizationManager"), assemblyInfo, new TextLocalizer());
+ StringExtensions.LocalizationManager = LocalizationManager;
+ RegisterSingleInstance(LocalizationManager);
+
+ ITextEncoding textEncoding = new TextEncoding(FileSystemManager);
+ RegisterSingleInstance(textEncoding);
+ Utilities.EncodingHelper = textEncoding;
+ RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer(FileSystemManager, textEncoding));
+
+ RegisterSingleInstance<IXmlReaderSettingsFactory>(new XmlReaderSettingsFactory());
+
+ UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager);
+ RegisterSingleInstance(UserDataManager);
+
+ UserRepository = await GetUserRepository().ConfigureAwait(false);
+
+ var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths, NativeApp.GetDbConnector(), MemoryStreamFactory);
+ DisplayPreferencesRepository = displayPreferencesRepo;
+ RegisterSingleInstance(DisplayPreferencesRepository);
+
+ var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager, NativeApp.GetDbConnector(), MemoryStreamFactory);
+ ItemRepository = itemRepo;
+ RegisterSingleInstance(ItemRepository);
+
+ 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, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider, _defaultUserNameFactory());
+ RegisterSingleInstance(UserManager);
+
+ LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
+ RegisterSingleInstance(LibraryManager);
+
+ var musicManager = new MusicManager(LibraryManager);
+ RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager));
+
+ LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, TimerFactory, SystemEvents, EnvironmentInfo);
+ RegisterSingleInstance(LibraryMonitor);
+
+ ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer, MemoryStreamFactory);
+ RegisterSingleInstance(ProviderManager);
+
+ RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
+
+ HttpServer = HttpServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, MemoryStreamFactory, "Emby", "web/index.html", textEncoding, SocketFactory, CryptographyProvider, JsonSerializer, XmlSerializer, EnvironmentInfo, Certificate);
+ HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
+ RegisterSingleInstance(HttpServer, false);
+ progress.Report(10);
+
+ ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
+ RegisterSingleInstance(ServerManager);
+
+ var innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
+
+ ImageProcessor = GetImageProcessor();
+ RegisterSingleInstance(ImageProcessor);
+
+ TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
+ RegisterSingleInstance(TVSeriesManager);
+
+ SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager, () => MediaSourceManager, JsonSerializer, TaskManager, MemoryStreamFactory);
+ RegisterSingleInstance(SyncManager);
+
+ DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager, () => LiveTvManager);
+ RegisterSingleInstance(DtoService);
+
+ var encryptionManager = new EncryptionManager();
+ RegisterSingleInstance<IEncryptionManager>(encryptionManager);
+
+ ConnectManager = new ConnectManager(LogManager.GetLogger("ConnectManager"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager, FileSystemManager);
+ RegisterSingleInstance(ConnectManager);
+
+ DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
+ RegisterSingleInstance(DeviceManager);
+
+ var newsService = new Emby.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, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
+ RegisterSingleInstance(ChannelManager);
+
+ MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager, UserDataManager, TimerFactory);
+ RegisterSingleInstance(MediaSourceManager);
+
+ SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager, TimerFactory);
+ RegisterSingleInstance(SessionManager);
+
+ var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this, assemblyInfo);
+ RegisterSingleInstance<IDlnaManager>(dlnaManager);
+
+ var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient, new XmlReaderSettingsFactory());
+ RegisterSingleInstance<IConnectionManager>(connectionManager);
+
+ CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"), ProviderManager);
+ RegisterSingleInstance(CollectionManager);
+
+ PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager);
+ RegisterSingleInstance<IPlaylistManager>(PlaylistManager);
+
+ LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, SecurityManager);
+ RegisterSingleInstance(LiveTvManager);
+
+ UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
+ RegisterSingleInstance(UserViewManager);
+
+ var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory());
+ RegisterSingleInstance<IContentDirectory>(contentDirectory);
+
+ var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
+ RegisterSingleInstance<IMediaReceiverRegistrar>(mediaRegistrar);
+
+ NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
+ RegisterSingleInstance(NotificationManager);
+
+ SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager);
+ RegisterSingleInstance(SubtitleManager);
+
+ RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, SocketFactory, TimerFactory));
+
+ ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository);
+ RegisterSingleInstance(ChapterManager);
+
+ await RegisterMediaEncoder(innerProgress).ConfigureAwait(false);
+ progress.Report(90);
+
+ EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager, LibraryManager);
+ RegisterSingleInstance(EncodingManager);
+
+ var sharingRepo = new SharingRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
+ await sharingRepo.Initialize().ConfigureAwait(false);
+ RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
+
+ var activityLogRepo = await GetActivityLogRepository().ConfigureAwait(false);
+ RegisterSingleInstance(activityLogRepo);
+ RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
+
+ var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager);
+ RegisterSingleInstance<IAuthorizationContext>(authContext);
+ RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
+
+ AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager);
+ RegisterSingleInstance<IAuthService>(AuthService);
+
+ SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamFactory, ProcessFactory, textEncoding);
+ RegisterSingleInstance(SubtitleEncoder);
+
+ await displayPreferencesRepo.Initialize().ConfigureAwait(false);
+
+ var userDataRepo = new SqliteUserDataRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
+
+ ((UserDataManager)UserDataManager).Repository = userDataRepo;
+ await itemRepo.Initialize(userDataRepo).ConfigureAwait(false);
+ ((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
+ await ConfigureNotificationsRepository().ConfigureAwait(false);
+ progress.Report(100);
+
+ SetStaticProperties();
+
+ await ((UserManager)UserManager).Initialize().ConfigureAwait(false);
+ }
+
+ private ICertificate GetCertificate(string certificateLocation)
+ {
+ if (string.IsNullOrWhiteSpace(certificateLocation))
+ {
+ return null;
+ }
+
+ try
+ {
+ X509Certificate2 localCert = new X509Certificate2(certificateLocation);
+ //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
+ if (!localCert.HasPrivateKey)
+ {
+ //throw new FileNotFoundException("Secure requested, no private key included", certificateLocation);
+ return null;
+ }
+
+ return new Certificate(localCert);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading cert from {0}", ex, certificateLocation);
+ return null;
+ }
+ }
+
+ private IImageProcessor GetImageProcessor()
+ {
+ var maxConcurrentImageProcesses = Math.Max(Environment.ProcessorCount, 4);
+
+ if (_startupOptions.ContainsOption("-imagethreads"))
+ {
+ int.TryParse(_startupOptions.GetOption("-imagethreads"), NumberStyles.Any, CultureInfo.InvariantCulture, out maxConcurrentImageProcesses);
+ }
+
+ return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, maxConcurrentImageProcesses, () => LibraryManager, TimerFactory);
+ }
+
+ /// <summary>
+ /// Registers the media encoder.
+ /// </summary>
+ /// <returns>Task.</returns>
+ private async Task RegisterMediaEncoder(IProgress<double> progress)
+ {
+ string encoderPath = null;
+ string probePath = null;
+
+ var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.GetFfmpegInstallInfo())
+ .GetFFMpegInfo(_startupOptions, progress).ConfigureAwait(false);
+
+ encoderPath = info.EncoderPath;
+ probePath = info.ProbePath;
+ var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
+
+ var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
+ JsonSerializer,
+ encoderPath,
+ probePath,
+ hasExternalEncoder,
+ ServerConfigurationManager,
+ FileSystemManager,
+ LiveTvManager,
+ IsoManager,
+ LibraryManager,
+ ChannelManager,
+ SessionManager,
+ () => SubtitleEncoder,
+ () => MediaSourceManager,
+ HttpClient,
+ ZipClient,
+ MemoryStreamFactory,
+ ProcessFactory,
+ (Environment.ProcessorCount > 2 ? 14000 : 40000),
+ EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows);
+
+ MediaEncoder = mediaEncoder;
+ RegisterSingleInstance(MediaEncoder);
+ }
+
+ /// <summary>
+ /// Gets the user repository.
+ /// </summary>
+ /// <returns>Task{IUserRepository}.</returns>
+ private async Task<IUserRepository> GetUserRepository()
+ {
+ var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector(), MemoryStreamFactory);
+
+ 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, NativeApp.GetDbConnector());
+
+ await repo.Initialize().ConfigureAwait(false);
+
+ return repo;
+ }
+
+ private async Task<IAuthenticationRepository> GetAuthenticationRepository()
+ {
+ var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
+
+ await repo.Initialize().ConfigureAwait(false);
+
+ return repo;
+ }
+
+ private async Task<IActivityRepository> GetActivityLogRepository()
+ {
+ var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
+
+ await repo.Initialize().ConfigureAwait(false);
+
+ return repo;
+ }
+
+ private async Task<ISyncRepository> GetSyncRepository()
+ {
+ var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
+
+ await repo.Initialize().ConfigureAwait(false);
+
+ return repo;
+ }
+
+ /// <summary>
+ /// Configures the repositories.
+ /// </summary>
+ private async Task ConfigureNotificationsRepository()
+ {
+ var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
+
+ await repo.Initialize().ConfigureAwait(false);
+
+ NotificationsRepository = repo;
+
+ RegisterSingleInstance(NotificationsRepository);
+ }
+
+ /// <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;
+ Folder.UserManager = UserManager;
+ BaseItem.FileSystem = FileSystemManager;
+ BaseItem.UserDataManager = UserDataManager;
+ BaseItem.ChannelManager = ChannelManager;
+ BaseItem.LiveTvManager = LiveTvManager;
+ Folder.UserViewManager = UserViewManager;
+ UserView.TVSeriesManager = TVSeriesManager;
+ UserView.PlaylistManager = PlaylistManager;
+ BaseItem.CollectionManager = CollectionManager;
+ BaseItem.MediaSourceManager = MediaSourceManager;
+ CollectionFolder.XmlSerializer = XmlSerializer;
+ BaseStreamingService.AppHost = this;
+ BaseStreamingService.HttpClient = HttpClient;
+ Utilities.CryptographyProvider = CryptographyProvider;
+ AuthenticatedAttribute.AuthService = AuthService;
+ }
+
+ /// <summary>
+ /// Finds the parts.
+ /// </summary>
+ protected override void FindParts()
+ {
+ if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
+ {
+ RegisterServerWithAdministratorAccess();
+ ServerConfigurationManager.Configuration.IsPortAuthorized = true;
+ ConfigurationManager.SaveConfiguration();
+ }
+
+ RegisterModules();
+
+ base.FindParts();
+
+ HttpServer.Init(GetExports<IService>(false));
+
+ ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false));
+
+ StartServer();
+
+ LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(),
+ GetExports<IVirtualFolderCreator>(),
+ GetExports<IItemResolver>(),
+ GetExports<IIntroProvider>(),
+ GetExports<IBaseItemComparer>(),
+ GetExports<ILibraryPostScanTask>());
+
+ ProviderManager.AddParts(GetExports<IImageProvider>(),
+ GetExports<IMetadataService>(),
+ GetExports<IMetadataProvider>(),
+ GetExports<IMetadataSaver>(),
+ GetExports<IExternalId>());
+
+ ImageProcessor.AddParts(GetExports<IImageEnhancer>());
+
+ LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
+
+ SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
+
+ SessionManager.AddParts(GetExports<ISessionControllerFactory>());
+
+ ChannelManager.AddParts(GetExports<IChannel>());
+
+ MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
+
+ NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
+ SyncManager.AddParts(GetExports<ISyncProvider>());
+ }
+
+ private string CertificatePath { get; set; }
+ private ICertificate Certificate { get; set; }
+
+ private IEnumerable<string> GetUrlPrefixes()
+ {
+ var hosts = new List<string>();
+
+ hosts.Add("+");
+
+ return hosts.SelectMany(i =>
+ {
+ var prefixes = new List<string>
+ {
+ "http://"+i+":" + HttpPort + "/"
+ };
+
+ if (!string.IsNullOrWhiteSpace(CertificatePath))
+ {
+ prefixes.Add("https://" + i + ":" + HttpsPort + "/");
+ }
+
+ return prefixes;
+ });
+ }
+
+ /// <summary>
+ /// Starts the server.
+ /// </summary>
+ private void StartServer()
+ {
+ CertificatePath = GetCertificatePath(true);
+ Certificate = GetCertificate(CertificatePath);
+
+ try
+ {
+ ServerManager.Start(GetUrlPrefixes());
+ return;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error starting http server", ex);
+
+ if (HttpPort == ServerConfiguration.DefaultHttpPort)
+ {
+ throw;
+ }
+ }
+
+ HttpPort = ServerConfiguration.DefaultHttpPort;
+
+ try
+ {
+ ServerManager.Start(GetUrlPrefixes());
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error starting http server", ex);
+
+ throw;
+ }
+ }
+
+ private string GetCertificatePath(bool generateCertificate)
+ {
+ if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePath))
+ {
+ // Custom cert
+ return ServerConfigurationManager.Configuration.CertificatePath;
+ }
+
+ // Generate self-signed cert
+ var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns);
+ var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "1").GetMD5().ToString("N") + ".pfx");
+
+ if (generateCertificate)
+ {
+ if (!FileSystemManager.FileExists(certPath))
+ {
+ FileSystemManager.CreateDirectory(Path.GetDirectoryName(certPath));
+
+ try
+ {
+ _certificateGenerator(certPath, certHost);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error creating ssl cert", ex);
+ return null;
+ }
+ }
+ }
+
+ return certPath;
+ }
+
+ /// <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);
+
+ var requiresRestart = false;
+
+ // Don't do anything if these haven't been set yet
+ if (HttpPort != 0 && HttpsPort != 0)
+ {
+ // Need to restart if ports have changed
+ if (ServerConfigurationManager.Configuration.HttpServerPortNumber != HttpPort ||
+ ServerConfigurationManager.Configuration.HttpsPortNumber != HttpsPort)
+ {
+ if (ServerConfigurationManager.Configuration.IsPortAuthorized)
+ {
+ ServerConfigurationManager.Configuration.IsPortAuthorized = false;
+ ServerConfigurationManager.SaveConfiguration();
+
+ requiresRestart = true;
+ }
+ }
+ }
+
+ if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
+ {
+ requiresRestart = true;
+ }
+
+ if (!string.Equals(CertificatePath, GetCertificatePath(false), StringComparison.OrdinalIgnoreCase))
+ {
+ requiresRestart = true;
+ }
+
+ if (requiresRestart)
+ {
+ NotifyPendingRestart();
+ }
+ }
+
+ /// <summary>
+ /// Restarts this instance.
+ /// </summary>
+ public override async Task Restart()
+ {
+ if (!CanSelfRestart)
+ {
+ throw new PlatformNotSupportedException("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.Info("Calling NativeApp.Restart");
+
+ NativeApp.Restart(_startupOptions);
+ }
+
+ /// <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(GetAssembly(typeof(ApiEntryPoint)));
+
+ // Include composable parts in the Dashboard assembly
+ list.Add(GetAssembly(typeof(DashboardService)));
+
+ // Include composable parts in the Model assembly
+ list.Add(GetAssembly(typeof(SystemInfo)));
+
+ // Include composable parts in the Common assembly
+ list.Add(GetAssembly(typeof(IApplicationHost)));
+
+ // Include composable parts in the Controller assembly
+ list.Add(GetAssembly(typeof(IServerApplicationHost)));
+
+ // Include composable parts in the Providers assembly
+ list.Add(GetAssembly(typeof(ProviderUtils)));
+
+ // Include composable parts in the Photos assembly
+ list.Add(GetAssembly(typeof(PhotoProvider)));
+
+ // Common implementations
+ list.Add(GetAssembly(typeof(TaskManager)));
+
+ // Emby.Server implementations
+ list.Add(GetAssembly(typeof(InstallationManager)));
+
+ // Emby.Server.Core
+ list.Add(GetAssembly(typeof(ServerApplicationPaths)));
+
+ // MediaEncoding
+ list.Add(GetAssembly(typeof(MediaEncoder)));
+
+ // Dlna
+ list.Add(GetAssembly(typeof(DlnaEntryPoint)));
+
+ // Local metadata
+ list.Add(GetAssembly(typeof(BoxSetXmlSaver)));
+
+ // Xbmc
+ list.Add(GetAssembly(typeof(ArtistNfoProvider)));
+
+ list.AddRange(NativeApp.GetAssembliesWithParts());
+
+ // Include composable parts in the running assembly
+ list.Add(GetAssembly(GetType()));
+
+ 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)
+ .Where(EnablePlugin)
+ .Select(LoadAssembly)
+ .Where(a => a != null)
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<Assembly>();
+ }
+ }
+
+ private bool EnablePlugin(string path)
+ {
+ var filename = Path.GetFileName(path);
+
+ var exclude = new[]
+ {
+ "mbplus.dll",
+ "mbintros.dll"
+ };
+
+ return !exclude.Contains(filename ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ }
+
+ /// <summary>
+ /// Gets the system status.
+ /// </summary>
+ /// <returns>SystemInfo.</returns>
+ public async Task<SystemInfo> GetSystemInfo()
+ {
+ var localAddress = await GetLocalApiUrl().ConfigureAwait(false);
+
+ return new SystemInfo
+ {
+ HasPendingRestart = HasPendingRestart,
+ Version = ApplicationVersion.ToString(),
+ IsNetworkDeployed = CanSelfUpdate,
+ WebSocketPortNumber = HttpPort,
+ 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 = HttpPort,
+ SupportsHttps = SupportsHttps,
+ HttpsPortNumber = HttpsPort,
+ OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
+ OperatingSystemDisplayName = OperatingSystemDisplayName,
+ CanSelfRestart = CanSelfRestart,
+ CanSelfUpdate = CanSelfUpdate,
+ WanAddress = ConnectManager.WanApiAddress,
+ HasUpdateAvailable = HasUpdateAvailable,
+ SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
+ TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
+ IsRunningAsService = IsRunningAsService,
+ SupportsRunningAsService = SupportsRunningAsService,
+ ServerName = FriendlyName,
+ LocalAddress = localAddress,
+ SupportsLibraryMonitor = true,
+ EncoderLocationType = MediaEncoder.EncoderLocationType,
+ SystemArchitecture = EnvironmentInfo.SystemArchitecture,
+ SystemUpdateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel,
+ PackageName = _startupOptions.GetOption("-package")
+ };
+ }
+
+ public bool EnableHttps
+ {
+ get
+ {
+ return SupportsHttps && ServerConfigurationManager.Configuration.EnableHttps;
+ }
+ }
+
+ public bool SupportsHttps
+ {
+ get { return Certificate != null; }
+ }
+
+ public async Task<string> GetLocalApiUrl()
+ {
+ try
+ {
+ // Return the first matched address, if found, or the first known local address
+ var address = (await GetLocalIpAddresses().ConfigureAwait(false)).FirstOrDefault(i => !i.Equals(IpAddressInfo.Loopback) && !i.Equals(IpAddressInfo.IPv6Loopback));
+
+ if (address != null)
+ {
+ return GetLocalApiUrl(address);
+ }
+
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error getting local Ip address information", ex);
+ }
+
+ return null;
+ }
+
+ public string GetLocalApiUrl(IpAddressInfo ipAddress)
+ {
+ if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ {
+ return GetLocalApiUrl("[" + ipAddress.Address + "]");
+ }
+
+ return GetLocalApiUrl(ipAddress.Address);
+ }
+
+ public string GetLocalApiUrl(string host)
+ {
+ return string.Format("http://{0}:{1}",
+ host,
+ HttpPort.ToString(CultureInfo.InvariantCulture));
+ }
+
+ public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
+ {
+ var addresses = NetworkManager.GetLocalIpAddresses().ToList();
+ var list = new List<IpAddressInfo>();
+
+ foreach (var address in addresses)
+ {
+ var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
+ if (valid)
+ {
+ list.Add(address);
+ }
+ }
+
+ return list;
+ }
+
+ private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
+ private DateTime _lastAddressCacheClear;
+ private async Task<bool> IsIpAddressValidAsync(IpAddressInfo address)
+ {
+ if (address.Equals(IpAddressInfo.Loopback) ||
+ address.Equals(IpAddressInfo.IPv6Loopback))
+ {
+ return true;
+ }
+
+ var apiUrl = GetLocalApiUrl(address);
+ apiUrl += "/system/ping";
+
+ if ((DateTime.UtcNow - _lastAddressCacheClear).TotalMinutes >= 15)
+ {
+ _lastAddressCacheClear = DateTime.UtcNow;
+ _validAddressResults.Clear();
+ }
+
+ bool cachedResult;
+ if (_validAddressResults.TryGetValue(apiUrl, out cachedResult))
+ {
+ return cachedResult;
+ }
+
+ try
+ {
+ using (var response = await HttpClient.SendAsync(new HttpRequestOptions
+ {
+ Url = apiUrl,
+ LogErrorResponseBody = false,
+ LogErrors = false,
+ LogRequest = false,
+ TimeoutMs = 30000,
+ BufferContent = false
+
+ }, "POST").ConfigureAwait(false))
+ {
+ using (var reader = new StreamReader(response.Content))
+ {
+ var result = reader.ReadToEnd();
+ var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
+
+ _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
+ //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
+ return valid;
+ }
+ }
+ }
+ catch
+ {
+ //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
+
+ _validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false);
+ return false;
+ }
+ }
+
+ public string FriendlyName
+ {
+ get
+ {
+ return string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.ServerName)
+ ? Environment.MachineName
+ : ServerConfigurationManager.Configuration.ServerName;
+ }
+ }
+
+ public int HttpPort { get; private set; }
+
+ public int HttpsPort { get; private set; }
+
+ /// <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
+ {
+ NativeApp.AuthorizeServer(
+ UdpServerEntryPoint.PortNumber,
+ ServerConfigurationManager.Configuration.HttpServerPortNumber,
+ ServerConfigurationManager.Configuration.HttpsPortNumber,
+ ConfigurationManager.CommonApplicationPaths.ApplicationPath,
+ 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 cacheLength = TimeSpan.FromHours(3);
+ var updateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel;
+
+ if (updateLevel == PackageVersionClass.Beta)
+ {
+ cacheLength = TimeSpan.FromHours(1);
+ }
+ else if (updateLevel == PackageVersionClass.Dev)
+ {
+ cacheLength = TimeSpan.FromMinutes(5);
+ }
+
+ var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser", "Emby", ApplicationVersion, updateLevel, _releaseAssetFilename,
+ "MBServer", "Mbserver.zip", cacheLength, cancellationToken).ConfigureAwait(false);
+
+ HasUpdateAvailable = result.IsUpdateAvailable;
+
+ 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>
+ public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ await InstallationManager.InstallPackage(package, false, 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)
+ {
+ NativeApp.ConfigureAutoRun(autorun);
+ }
+ }
+
+ /// <summary>
+ /// This returns localhost in the case of no external dns, and the hostname if the
+ /// dns is prefixed with a valid Uri prefix.
+ /// </summary>
+ /// <param name="externalDns">The external dns prefix to get the hostname of.</param>
+ /// <returns>The hostname in <paramref name="externalDns"/></returns>
+ private static string GetHostnameFromExternalDns(string externalDns)
+ {
+ if (string.IsNullOrWhiteSpace(externalDns))
+ {
+ return "localhost";
+ }
+
+ try
+ {
+ return new Uri(externalDns).Host;
+ }
+ catch
+ {
+ return externalDns;
+ }
+ }
+
+ public void LaunchUrl(string url)
+ {
+ NativeApp.LaunchUrl(url);
+ }
+
+ public void EnableLoopback(string appName)
+ {
+ NativeApp.EnableLoopback(appName);
+ }
+
+ private void RegisterModules()
+ {
+ var moduleTypes = GetExportTypes<IDependencyModule>();
+
+ foreach (var type in moduleTypes)
+ {
+ try
+ {
+ var instance = Activator.CreateInstance(type) as IDependencyModule;
+ if (instance != null)
+ instance.BindDependencies(this);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error setting up dependency bindings for " + type.Name, ex);
+ }
+ }
+ }
+
+ void IDependencyContainer.RegisterSingleInstance<T>(T obj, bool manageLifetime)
+ {
+ RegisterSingleInstance(obj, manageLifetime);
+ }
+
+ void IDependencyContainer.RegisterSingleInstance<T>(Func<T> func)
+ {
+ RegisterSingleInstance(func);
+ }
+
+ void IDependencyContainer.Register(Type typeInterface, Type typeImplementation)
+ {
+ Container.Register(typeInterface, typeImplementation);
+ }
+
+ }
+}