using MediaBrowser.Common.IO; using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Plugins; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.MediaInfo; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playback; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.ScheduledTasks; using MediaBrowser.Controller.Updates; using MediaBrowser.Controller.Weather; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Controller { /// /// Class Kernel /// public class Kernel : BaseKernel { /// /// The MB admin URL /// public const string MBAdminUrl = "http://mb3admin.com/admin/"; /// /// Gets the instance. /// /// The instance. public static Kernel Instance { get; private set; } /// /// Gets the library manager. /// /// The library manager. public LibraryManager LibraryManager { get; private set; } /// /// Gets the image manager. /// /// The image manager. public ImageManager ImageManager { get; private set; } /// /// Gets the user manager. /// /// The user manager. public UserManager UserManager { get; private set; } /// /// Gets the FFMPEG controller. /// /// The FFMPEG controller. public FFMpegManager FFMpegManager { get; private set; } /// /// Gets the installation manager. /// /// The installation manager. public InstallationManager InstallationManager { get; private set; } /// /// Gets or sets the file system manager. /// /// The file system manager. public FileSystemManager FileSystemManager { get; private set; } /// /// Gets the provider manager. /// /// The provider manager. public ProviderManager ProviderManager { get; private set; } /// /// Gets the user data manager. /// /// The user data manager. public UserDataManager UserDataManager { get; private set; } /// /// Gets the plug-in security manager. /// /// The plug-in security manager. public PluginSecurityManager PluginSecurityManager { get; private set; } /// /// The _users /// private IEnumerable _users; /// /// The _user lock /// private object _usersSyncLock = new object(); /// /// The _users initialized /// private bool _usersInitialized; /// /// Gets the users. /// /// The users. public IEnumerable Users { get { // Call ToList to exhaust the stream because we'll be iterating over this multiple times LazyInitializer.EnsureInitialized(ref _users, ref _usersInitialized, ref _usersSyncLock, UserManager.LoadUsers); return _users; } internal set { _users = value; if (value == null) { _usersInitialized = false; } } } /// /// The _root folder /// private AggregateFolder _rootFolder; /// /// The _root folder sync lock /// private object _rootFolderSyncLock = new object(); /// /// The _root folder initialized /// private bool _rootFolderInitialized; /// /// Gets the root folder. /// /// The root folder. public AggregateFolder RootFolder { get { LazyInitializer.EnsureInitialized(ref _rootFolder, ref _rootFolderInitialized, ref _rootFolderSyncLock, LibraryManager.CreateRootFolder); return _rootFolder; } private set { _rootFolder = value; if (value == null) { _rootFolderInitialized = false; } } } /// /// Gets the kernel context. /// /// The kernel context. public override KernelContext KernelContext { get { return KernelContext.Server; } } /// /// Gets the list of plugin configuration pages /// /// The configuration pages. [ImportMany(typeof(IPluginConfigurationPage))] public IEnumerable PluginConfigurationPages { get; private set; } /// /// Gets the intro providers. /// /// The intro providers. [ImportMany(typeof(IIntroProvider))] public IEnumerable IntroProviders { get; private set; } /// /// Gets the list of currently registered weather prvoiders /// /// The weather providers. [ImportMany(typeof(IWeatherProvider))] public IEnumerable WeatherProviders { get; private set; } /// /// Gets the list of currently registered metadata prvoiders /// /// The metadata providers enumerable. [ImportMany(typeof(BaseMetadataProvider))] public BaseMetadataProvider[] MetadataProviders { get; private set; } /// /// Gets the list of currently registered image processors /// Image processors are specialized metadata providers that run after the normal ones /// /// The image enhancers. [ImportMany(typeof(BaseImageEnhancer))] public BaseImageEnhancer[] ImageEnhancers { get; private set; } /// /// Gets the list of currently registered entity resolvers /// /// The entity resolvers enumerable. [ImportMany(typeof(IBaseItemResolver))] internal IBaseItemResolver[] EntityResolvers { get; private set; } /// /// Gets the list of BasePluginFolders added by plugins /// /// The plugin folders. [ImportMany(typeof(BasePluginFolder))] internal IEnumerable PluginFolders { get; private set; } /// /// Gets the list of available user repositories /// /// The user repositories. [ImportMany(typeof(IUserRepository))] private IEnumerable UserRepositories { get; set; } /// /// Gets the active user repository /// /// The user repository. public IUserRepository UserRepository { get; private set; } /// /// Gets the active user repository /// /// The display preferences repository. public IDisplayPreferencesRepository DisplayPreferencesRepository { get; private set; } /// /// Gets the list of available item repositories /// /// The item repositories. [ImportMany(typeof(IItemRepository))] private IEnumerable ItemRepositories { get; set; } /// /// Gets the active item repository /// /// The item repository. public IItemRepository ItemRepository { get; private set; } /// /// Gets the list of available item repositories /// /// The user data repositories. [ImportMany(typeof(IUserDataRepository))] private IEnumerable UserDataRepositories { get; set; } /// /// Gets the list of available DisplayPreferencesRepositories /// /// The display preferences repositories. [ImportMany(typeof(IDisplayPreferencesRepository))] private IEnumerable DisplayPreferencesRepositories { get; set; } /// /// Gets the list of entity resolution ignore rules /// /// The entity resolution ignore rules. [ImportMany(typeof(BaseResolutionIgnoreRule))] internal IEnumerable EntityResolutionIgnoreRules { get; private set; } /// /// Gets the active user data repository /// /// The user data repository. public IUserDataRepository UserDataRepository { get; private set; } /// /// Limits simultaneous access to various resources /// /// The resource pools. public ResourcePool ResourcePools { get; set; } /// /// Gets the UDP server port number. /// /// The UDP server port number. public override int UdpServerPortNumber { get { return 7359; } } /// /// Gets or sets the zip client. /// /// The zip client. private IZipClient ZipClient { get; set; } /// /// Gets or sets the bluray examiner. /// /// The bluray examiner. private IBlurayExaminer BlurayExaminer { get; set; } /// /// Creates a kernel based on a Data path, which is akin to our current programdata path /// /// The app host. /// The iso manager. /// The zip client. /// The bluray examiner. /// The logger. /// isoManager public Kernel(IApplicationHost appHost, IIsoManager isoManager, IZipClient zipClient, IBlurayExaminer blurayExaminer, ILogger logger) : base(appHost, isoManager, logger) { if (isoManager == null) { throw new ArgumentNullException("isoManager"); } if (zipClient == null) { throw new ArgumentNullException("zipClient"); } if (blurayExaminer == null) { throw new ArgumentNullException("blurayExaminer"); } Instance = this; ZipClient = zipClient; BlurayExaminer = blurayExaminer; // For now there's no real way to inject this properly BaseItem.Logger = logger; Ratings.Logger = logger; LocalizedStrings.Logger = logger; // For now, until this can become an interface BaseMetadataProvider.Logger = logger; } /// /// Composes the exported values. /// /// The container. protected override void ComposeExportedValues(CompositionContainer container) { base.ComposeExportedValues(container); container.ComposeExportedValue("kernel", this); container.ComposeExportedValue("blurayExaminer", BlurayExaminer); } /// /// Performs initializations that can be reloaded at anytime /// /// Task. protected override async Task ReloadInternal() { Logger.Info("Extracting tools"); // Reset these so that they can be lazy loaded again Users = null; RootFolder = null; ReloadResourcePools(); InstallationManager = new InstallationManager(this, ZipClient, Logger); LibraryManager = new LibraryManager(this, Logger); UserManager = new UserManager(this, Logger); FFMpegManager = new FFMpegManager(this, ZipClient, Logger); ImageManager = new ImageManager(this, Logger); ProviderManager = new ProviderManager(this, Logger); UserDataManager = new UserDataManager(this, Logger); PluginSecurityManager = new PluginSecurityManager(this); await base.ReloadInternal().ConfigureAwait(false); ReloadFileSystemManager(); await UserManager.RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false); } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool dispose) { if (dispose) { DisposeResourcePools(); DisposeFileSystemManager(); } base.Dispose(dispose); } /// /// Disposes the resource pools. /// private void DisposeResourcePools() { if (ResourcePools != null) { ResourcePools.Dispose(); ResourcePools = null; } } /// /// Reloads the resource pools. /// private void ReloadResourcePools() { DisposeResourcePools(); ResourcePools = new ResourcePool(); } /// /// Called when [composable parts loaded]. /// /// Task. protected override async Task OnComposablePartsLoaded() { // The base class will start up all the plugins await base.OnComposablePartsLoaded().ConfigureAwait(false); // Get the current item repository ItemRepository = GetRepository(ItemRepositories, Configuration.ItemRepository); var itemRepoTask = ItemRepository.Initialize(); // Get the current user repository UserRepository = GetRepository(UserRepositories, Configuration.UserRepository); var userRepoTask = UserRepository.Initialize(); // Get the current item repository UserDataRepository = GetRepository(UserDataRepositories, Configuration.UserDataRepository); var userDataRepoTask = UserDataRepository.Initialize(); // Get the current display preferences repository DisplayPreferencesRepository = GetRepository(DisplayPreferencesRepositories, Configuration.DisplayPreferencesRepository); var displayPreferencesRepoTask = DisplayPreferencesRepository.Initialize(); // Sort the resolvers by priority EntityResolvers = EntityResolvers.OrderBy(e => e.Priority).ToArray(); // Sort the providers by priority MetadataProviders = MetadataProviders.OrderBy(e => e.Priority).ToArray(); // Sort the image processors by priority ImageEnhancers = ImageEnhancers.OrderBy(e => e.Priority).ToArray(); await Task.WhenAll(itemRepoTask, userRepoTask, userDataRepoTask, displayPreferencesRepoTask).ConfigureAwait(false); } /// /// Gets a repository by name from a list, and returns the default if not found /// /// /// The repositories. /// The name. /// ``0. private T GetRepository(IEnumerable repositories, string name) where T : class, IRepository { var enumerable = repositories as T[] ?? repositories.ToArray(); return enumerable.FirstOrDefault(r => string.Equals(r.Name, name, StringComparison.OrdinalIgnoreCase)) ?? enumerable.FirstOrDefault(); } /// /// Disposes the file system manager. /// private void DisposeFileSystemManager() { if (FileSystemManager != null) { FileSystemManager.Dispose(); FileSystemManager = null; } } /// /// Reloads the file system manager. /// private void ReloadFileSystemManager() { DisposeFileSystemManager(); FileSystemManager = new FileSystemManager(this, Logger); FileSystemManager.StartWatchers(); } /// /// Gets a User by Id /// /// The id. /// User. /// public User GetUserById(Guid id) { if (id == Guid.Empty) { throw new ArgumentNullException(); } return Users.FirstOrDefault(u => u.Id == id); } /// /// Finds a library item by Id and UserId. /// /// The id. /// The user id. /// BaseItem. /// id public BaseItem GetItemById(Guid id, Guid userId) { if (id == Guid.Empty) { throw new ArgumentNullException("id"); } if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } var user = GetUserById(userId); var userRoot = user.RootFolder; return userRoot.FindItemById(id, user); } /// /// Gets the item by id. /// /// The id. /// BaseItem. /// id public BaseItem GetItemById(Guid id) { if (id == Guid.Empty) { throw new ArgumentNullException("id"); } return RootFolder.FindItemById(id, null); } /// /// Completely overwrites the current configuration with a new copy /// /// The config. public void UpdateConfiguration(ServerConfiguration config) { var oldConfiguration = Configuration; var reloadLogger = config.ShowLogWindow != oldConfiguration.ShowLogWindow; // Figure out whether or not we should refresh people after the update is finished var refreshPeopleAfterUpdate = !oldConfiguration.EnableInternetProviders && config.EnableInternetProviders; // This is true if internet providers has just been turned on, or if People have just been removed from InternetProviderExcludeTypes if (!refreshPeopleAfterUpdate) { var oldConfigurationFetchesPeopleImages = oldConfiguration.InternetProviderExcludeTypes == null || !oldConfiguration.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); var newConfigurationFetchesPeopleImages = config.InternetProviderExcludeTypes == null || !config.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); refreshPeopleAfterUpdate = newConfigurationFetchesPeopleImages && !oldConfigurationFetchesPeopleImages; } Configuration = config; SaveConfiguration(); if (reloadLogger) { ReloadLogger(); } TcpManager.OnApplicationConfigurationChanged(oldConfiguration, config); // Validate currently executing providers, in the background Task.Run(() => { ProviderManager.ValidateCurrentlyRunningProviders(); // Any number of configuration settings could change the way the library is refreshed, so do that now TaskManager.CancelIfRunningAndQueue(); if (refreshPeopleAfterUpdate) { TaskManager.CancelIfRunningAndQueue(); } }); } /// /// Removes the plugin. /// /// The plugin. internal void RemovePlugin(IPlugin plugin) { var list = Plugins.ToList(); list.Remove(plugin); Plugins = list; } /// /// Gets the system info. /// /// SystemInfo. public override SystemInfo GetSystemInfo() { var info = base.GetSystemInfo(); if (InstallationManager != null) { info.InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToArray(); info.CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(); } return info; } } }