Jelajahi Sumber

Merge pull request #2765 from mark-monteiro/register-services-correctly

Register And Construct Services Correctly Using DI Framework
Bond-009 5 tahun lalu
induk
melakukan
07c4dfd8fe
29 mengubah file dengan 503 tambahan dan 831 penghapusan
  1. 4 30
      Emby.Drawing/ImageProcessor.cs
  2. 1 1
      Emby.Photos/PhotoProvider.cs
  3. 188 414
      Emby.Server.Implementations/ApplicationHost.cs
  4. 6 7
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  5. 3 3
      Emby.Server.Implementations/Devices/DeviceManager.cs
  6. 16 14
      Emby.Server.Implementations/Dto/DtoService.cs
  7. 10 3
      Emby.Server.Implementations/EntryPoints/StartupWizard.cs
  8. 5 4
      Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
  9. 26 32
      Emby.Server.Implementations/IO/LibraryMonitor.cs
  10. 100 129
      Emby.Server.Implementations/Library/LibraryManager.cs
  11. 11 11
      Emby.Server.Implementations/Library/MediaSourceManager.cs
  12. 3 4
      Emby.Server.Implementations/Library/SearchEngine.cs
  13. 18 19
      Emby.Server.Implementations/Library/UserDataManager.cs
  14. 10 16
      Emby.Server.Implementations/Library/UserManager.cs
  15. 0 1
      Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
  16. 10 15
      Emby.Server.Implementations/LiveTv/LiveTvManager.cs
  17. 0 3
      Emby.Server.Implementations/Localization/LocalizationManager.cs
  18. 3 17
      Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
  19. 2 2
      Emby.Server.Implementations/Security/AuthenticationRepository.cs
  20. 13 4
      Jellyfin.Drawing.Skia/SkiaEncoder.cs
  21. 22 5
      Jellyfin.Server/CoreAppHost.cs
  22. 2 23
      Jellyfin.Server/Program.cs
  23. 8 1
      MediaBrowser.Api/Images/ImageService.cs
  24. 1 5
      MediaBrowser.Common/IApplicationHost.cs
  25. 0 9
      MediaBrowser.Controller/Drawing/IImageProcessor.cs
  26. 1 1
      MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
  27. 4 13
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  28. 32 41
      MediaBrowser.Providers/Manager/ProviderManager.cs
  29. 4 4
      MediaBrowser.Providers/Subtitles/SubtitleManager.cs

+ 4 - 30
Emby.Drawing/ImageProcessor.cs

@@ -8,7 +8,6 @@ using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
@@ -33,8 +32,7 @@ namespace Emby.Drawing
         private readonly IFileSystem _fileSystem;
         private readonly IServerApplicationPaths _appPaths;
         private readonly IImageEncoder _imageEncoder;
-        private readonly Func<ILibraryManager> _libraryManager;
-        private readonly Func<IMediaEncoder> _mediaEncoder;
+        private readonly IMediaEncoder _mediaEncoder;
 
         private bool _disposed = false;
 
@@ -45,20 +43,17 @@ namespace Emby.Drawing
         /// <param name="appPaths">The server application paths.</param>
         /// <param name="fileSystem">The filesystem.</param>
         /// <param name="imageEncoder">The image encoder.</param>
-        /// <param name="libraryManager">The library manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
         public ImageProcessor(
             ILogger<ImageProcessor> logger,
             IServerApplicationPaths appPaths,
             IFileSystem fileSystem,
             IImageEncoder imageEncoder,
-            Func<ILibraryManager> libraryManager,
-            Func<IMediaEncoder> mediaEncoder)
+            IMediaEncoder mediaEncoder)
         {
             _logger = logger;
             _fileSystem = fileSystem;
             _imageEncoder = imageEncoder;
-            _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
             _appPaths = appPaths;
         }
@@ -126,21 +121,9 @@ namespace Emby.Drawing
                 throw new ArgumentNullException(nameof(options));
             }
 
-            var libraryManager = _libraryManager();
-
             ItemImageInfo originalImage = options.Image;
             BaseItem item = options.Item;
 
-            if (!originalImage.IsLocalFile)
-            {
-                if (item == null)
-                {
-                    item = libraryManager.GetItemById(options.ItemId);
-                }
-
-                originalImage = await libraryManager.ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
-            }
-
             string originalImagePath = originalImage.Path;
             DateTime dateModified = originalImage.DateModified;
             ImageDimensions? originalImageSize = null;
@@ -312,10 +295,6 @@ namespace Emby.Drawing
 
         /// <inheritdoc />
         public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info)
-            => GetImageDimensions(item, info, true);
-
-        /// <inheritdoc />
-        public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem)
         {
             int width = info.Width;
             int height = info.Height;
@@ -332,11 +311,6 @@ namespace Emby.Drawing
             info.Width = size.Width;
             info.Height = size.Height;
 
-            if (updateItem)
-            {
-                _libraryManager().UpdateImages(item);
-            }
-
             return size;
         }
 
@@ -384,13 +358,13 @@ namespace Emby.Drawing
                 {
                     string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
 
-                    string cacheExtension = _mediaEncoder().SupportsEncoder("libwebp") ? ".webp" : ".png";
+                    string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png";
                     var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
 
                     var file = _fileSystem.GetFileInfo(outputPath);
                     if (!file.Exists)
                     {
-                        await _mediaEncoder().ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
+                        await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
                         dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
                     }
                     else

+ 1 - 1
Emby.Photos/PhotoProvider.cs

@@ -160,7 +160,7 @@ namespace Emby.Photos
 
                 try
                 {
-                    var size = _imageProcessor.GetImageDimensions(item, img, false);
+                    var size = _imageProcessor.GetImageDimensions(item, img);
 
                     if (size.Width > 0 && size.Height > 0)
                     {

+ 188 - 414
Emby.Server.Implementations/ApplicationHost.cs

@@ -86,7 +86,6 @@ using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Cryptography;
 using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
@@ -104,7 +103,6 @@ using MediaBrowser.WebDashboard.Api;
 using MediaBrowser.XbmcMetadata.Providers;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Extensions;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
@@ -121,14 +119,20 @@ namespace Emby.Server.Implementations
         /// </summary>
         private static readonly string[] _relevantEnvVarPrefixes = { "JELLYFIN_", "DOTNET_", "ASPNETCORE_" };
 
-        private SqliteUserRepository _userRepository;
-        private SqliteDisplayPreferencesRepository _displayPreferencesRepository;
+        private readonly IFileSystem _fileSystemManager;
+        private readonly INetworkManager _networkManager;
+        private readonly IXmlSerializer _xmlSerializer;
+        private readonly IStartupOptions _startupOptions;
+
+        private IMediaEncoder _mediaEncoder;
+        private ISessionManager _sessionManager;
+        private IHttpServer _httpServer;
+        private IHttpClient _httpClient;
 
         /// <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 abstract bool CanSelfRestart { get; }
+        public bool CanSelfRestart => _startupOptions.RestartPath != null;
 
         public virtual bool CanLaunchWebBrowser
         {
@@ -139,7 +143,7 @@ namespace Emby.Server.Implementations
                     return false;
                 }
 
-                if (StartupOptions.IsService)
+                if (_startupOptions.IsService)
                 {
                     return false;
                 }
@@ -209,8 +213,6 @@ namespace Emby.Server.Implementations
         /// <value>The configuration manager.</value>
         protected IConfigurationManager ConfigurationManager { get; set; }
 
-        public IFileSystem FileSystemManager { get; set; }
-
         /// <summary>
         /// Gets or sets the service provider.
         /// </summary>
@@ -232,110 +234,6 @@ namespace Emby.Server.Implementations
         /// <value>The server configuration manager.</value>
         public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
 
-        /// <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; }
-
-        public 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 ISessionManager SessionManager { get; set; }
-
-        private ILiveTvManager LiveTvManager { get; set; }
-
-        public LocalizationManager LocalizationManager { get; set; }
-
-        private IEncodingManager EncodingManager { get; set; }
-
-        private IChannelManager ChannelManager { get; set; }
-
-        /// <summary>
-        /// Gets or sets the user data repository.
-        /// </summary>
-        /// <value>The user data repository.</value>
-        private IUserDataManager UserDataManager { get; set; }
-
-        internal SqliteItemRepository ItemRepository { 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 ITVSeriesManager TVSeriesManager { get; set; }
-
-        private ICollectionManager CollectionManager { get; set; }
-
-        private IMediaSourceManager MediaSourceManager { get; set; }
-
-        /// <summary>
-        /// Gets the installation manager.
-        /// </summary>
-        /// <value>The installation manager.</value>
-        protected IInstallationManager InstallationManager { get; private set; }
-
-        protected IAuthService AuthService { get; private set; }
-
-        public IStartupOptions StartupOptions { get; }
-
-        internal IImageEncoder ImageEncoder { get; private set; }
-
-        protected readonly IXmlSerializer XmlSerializer;
-
-        protected ISocketFactory SocketFactory { get; private set; }
-
-        protected ITaskManager TaskManager { get; private set; }
-
-        public IHttpClient HttpClient { get; private set; }
-
-        protected INetworkManager NetworkManager { get; set; }
-
-        public IJsonSerializer JsonSerializer { get; private set; }
-
-        protected IIsoManager IsoManager { get; private set; }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
         /// </summary>
@@ -344,29 +242,33 @@ namespace Emby.Server.Implementations
             ILoggerFactory loggerFactory,
             IStartupOptions options,
             IFileSystem fileSystem,
-            IImageEncoder imageEncoder,
             INetworkManager networkManager)
         {
-            XmlSerializer = new MyXmlSerializer();
+            _xmlSerializer = new MyXmlSerializer();
 
-            NetworkManager = networkManager;
+            _networkManager = networkManager;
             networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
 
             ApplicationPaths = applicationPaths;
             LoggerFactory = loggerFactory;
-            FileSystemManager = fileSystem;
+            _fileSystemManager = fileSystem;
 
-            ConfigurationManager = new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager);
+            ConfigurationManager = new ServerConfigurationManager(ApplicationPaths, LoggerFactory, _xmlSerializer, _fileSystemManager);
 
-            Logger = LoggerFactory.CreateLogger("App");
+            Logger = LoggerFactory.CreateLogger<ApplicationHost>();
 
-            StartupOptions = options;
-
-            ImageEncoder = imageEncoder;
+            _startupOptions = options;
 
             fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
 
-            NetworkManager.NetworkChanged += OnNetworkChanged;
+            _networkManager.NetworkChanged += OnNetworkChanged;
+
+            CertificateInfo = new CertificateInfo
+            {
+                Path = ServerConfigurationManager.Configuration.CertificatePath,
+                Password = ServerConfigurationManager.Configuration.CertificatePassword
+            };
+            Certificate = GetCertificate(CertificateInfo);
         }
 
         public string ExpandVirtualPath(string path)
@@ -434,10 +336,7 @@ namespace Emby.Server.Implementations
             }
         }
 
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
+        /// <inheritdoc/>
         public string Name => ApplicationProductName;
 
         /// <summary>
@@ -527,7 +426,7 @@ namespace Emby.Server.Implementations
 
             ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
 
-            MediaEncoder.SetFFmpegPath();
+            _mediaEncoder.SetFFmpegPath();
 
             Logger.LogInformation("ServerId: {0}", SystemId);
 
@@ -539,7 +438,7 @@ namespace Emby.Server.Implementations
             Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
 
             Logger.LogInformation("Core startup complete");
-            HttpServer.GlobalResponse = null;
+            _httpServer.GlobalResponse = null;
 
             stopWatch.Restart();
             await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false);
@@ -563,7 +462,7 @@ namespace Emby.Server.Implementations
         }
 
         /// <inheritdoc/>
-        public async Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig)
+        public void Init(IServiceCollection serviceCollection)
         {
             HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
             HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -575,8 +474,6 @@ namespace Emby.Server.Implementations
                 HttpsPort = ServerConfiguration.DefaultHttpsPort;
             }
 
-            JsonSerializer = new JsonSerializer();
-
             if (Plugins != null)
             {
                 var pluginBuilder = new StringBuilder();
@@ -596,7 +493,7 @@ namespace Emby.Server.Implementations
 
             DiscoverTypes();
 
-            await RegisterServices(serviceCollection, startupConfig).ConfigureAwait(false);
+            RegisterServices(serviceCollection);
         }
 
         public async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func<Task> next)
@@ -607,7 +504,7 @@ namespace Emby.Server.Implementations
                 return;
             }
 
-            await HttpServer.ProcessWebSocketRequest(context).ConfigureAwait(false);
+            await _httpServer.ProcessWebSocketRequest(context).ConfigureAwait(false);
         }
 
         public async Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
@@ -623,14 +520,16 @@ namespace Emby.Server.Implementations
             var localPath = context.Request.Path.ToString();
 
             var req = new WebSocketSharpRequest(request, response, request.Path, LoggerFactory.CreateLogger<WebSocketSharpRequest>());
-            await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
+            await _httpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
         }
 
         /// <summary>
         /// Registers services/resources with the service collection that will be available via DI.
         /// </summary>
-        protected async Task RegisterServices(IServiceCollection serviceCollection, IConfiguration startupConfig)
+        protected virtual void RegisterServices(IServiceCollection serviceCollection)
         {
+            serviceCollection.AddSingleton(_startupOptions);
+
             serviceCollection.AddMemoryCache();
 
             serviceCollection.AddSingleton(ConfigurationManager);
@@ -638,240 +537,169 @@ namespace Emby.Server.Implementations
 
             serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
 
-            serviceCollection.AddSingleton(JsonSerializer);
+            serviceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
 
-            // TODO: Support for injecting ILogger should be deprecated in favour of ILogger<T> and this removed
-            serviceCollection.AddSingleton<ILogger>(Logger);
+            // TODO: Remove support for injecting ILogger completely
+            serviceCollection.AddSingleton((provider) =>
+            {
+                Logger.LogWarning("Injecting ILogger directly is deprecated and should be replaced with ILogger<T>");
+                return Logger;
+            });
 
-            serviceCollection.AddSingleton(FileSystemManager);
+            serviceCollection.AddSingleton(_fileSystemManager);
             serviceCollection.AddSingleton<TvdbClientManager>();
 
-            HttpClient = new HttpClientManager.HttpClientManager(
-                ApplicationPaths,
-                LoggerFactory.CreateLogger<HttpClientManager.HttpClientManager>(),
-                FileSystemManager,
-                () => ApplicationUserAgent);
-            serviceCollection.AddSingleton(HttpClient);
+            serviceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
 
-            serviceCollection.AddSingleton(NetworkManager);
+            serviceCollection.AddSingleton(_networkManager);
 
-            IsoManager = new IsoManager();
-            serviceCollection.AddSingleton(IsoManager);
+            serviceCollection.AddSingleton<IIsoManager, IsoManager>();
 
-            TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LoggerFactory, FileSystemManager);
-            serviceCollection.AddSingleton(TaskManager);
+            serviceCollection.AddSingleton<ITaskManager, TaskManager>();
 
-            serviceCollection.AddSingleton(XmlSerializer);
+            serviceCollection.AddSingleton(_xmlSerializer);
 
-            serviceCollection.AddSingleton(typeof(IStreamHelper), typeof(StreamHelper));
+            serviceCollection.AddSingleton<IStreamHelper, StreamHelper>();
 
-            var cryptoProvider = new CryptographyProvider();
-            serviceCollection.AddSingleton<ICryptoProvider>(cryptoProvider);
+            serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
 
-            SocketFactory = new SocketFactory();
-            serviceCollection.AddSingleton(SocketFactory);
+            serviceCollection.AddSingleton<ISocketFactory, SocketFactory>();
 
-            serviceCollection.AddSingleton(typeof(IInstallationManager), typeof(InstallationManager));
+            serviceCollection.AddSingleton<IInstallationManager, InstallationManager>();
 
-            serviceCollection.AddSingleton(typeof(IZipClient), typeof(ZipClient));
+            serviceCollection.AddSingleton<IZipClient, ZipClient>();
 
-            serviceCollection.AddSingleton(typeof(IHttpResultFactory), typeof(HttpResultFactory));
+            serviceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
 
             serviceCollection.AddSingleton<IServerApplicationHost>(this);
             serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
 
             serviceCollection.AddSingleton(ServerConfigurationManager);
 
-            LocalizationManager = new LocalizationManager(ServerConfigurationManager, JsonSerializer, LoggerFactory.CreateLogger<LocalizationManager>());
-            await LocalizationManager.LoadAll().ConfigureAwait(false);
-            serviceCollection.AddSingleton<ILocalizationManager>(LocalizationManager);
-
-            serviceCollection.AddSingleton<IBlurayExaminer>(new BdInfoExaminer(FileSystemManager));
+            serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
 
-            UserDataManager = new UserDataManager(LoggerFactory, ServerConfigurationManager, () => UserManager);
-            serviceCollection.AddSingleton(UserDataManager);
+            serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
 
-            _displayPreferencesRepository = new SqliteDisplayPreferencesRepository(
-                LoggerFactory.CreateLogger<SqliteDisplayPreferencesRepository>(),
-                ApplicationPaths,
-                FileSystemManager);
-            serviceCollection.AddSingleton<IDisplayPreferencesRepository>(_displayPreferencesRepository);
+            serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
+            serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
 
-            ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, LoggerFactory.CreateLogger<SqliteItemRepository>(), LocalizationManager);
-            serviceCollection.AddSingleton<IItemRepository>(ItemRepository);
+            serviceCollection.AddSingleton<IDisplayPreferencesRepository, SqliteDisplayPreferencesRepository>();
 
-            AuthenticationRepository = GetAuthenticationRepository();
-            serviceCollection.AddSingleton(AuthenticationRepository);
+            serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
 
-            _userRepository = GetUserRepository();
+            serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
 
-            UserManager = new UserManager(
-                LoggerFactory.CreateLogger<UserManager>(),
-                _userRepository,
-                XmlSerializer,
-                NetworkManager,
-                () => ImageProcessor,
-                () => DtoService,
-                this,
-                JsonSerializer,
-                FileSystemManager,
-                cryptoProvider);
+            serviceCollection.AddSingleton<IUserRepository, SqliteUserRepository>();
 
-            serviceCollection.AddSingleton(UserManager);
+            // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
+            serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
+            serviceCollection.AddSingleton<IUserManager, UserManager>();
 
-            MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
-                LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
-                ServerConfigurationManager,
-                FileSystemManager,
-                LocalizationManager,
-                () => SubtitleEncoder,
-                startupConfig,
-                StartupOptions.FFmpegPath);
-            serviceCollection.AddSingleton(MediaEncoder);
+            // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
+            // TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation
+            serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
+            serviceCollection.AddSingleton<IMediaEncoder>(provider =>
+                ActivatorUtilities.CreateInstance<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(provider, _startupOptions.FFmpegPath ?? string.Empty));
 
-            LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager, MediaEncoder);
-            serviceCollection.AddSingleton(LibraryManager);
+            // TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
+            serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
+            serviceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
+            serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
+            serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
 
-            var musicManager = new MusicManager(LibraryManager);
-            serviceCollection.AddSingleton<IMusicManager>(musicManager);
+            serviceCollection.AddSingleton<IMusicManager, MusicManager>();
 
-            LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
-            serviceCollection.AddSingleton(LibraryMonitor);
+            serviceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
 
-            serviceCollection.AddSingleton<ISearchEngine>(new SearchEngine(LoggerFactory, LibraryManager, UserManager));
-
-            CertificateInfo = GetCertificateInfo(true);
-            Certificate = GetCertificate(CertificateInfo);
+            serviceCollection.AddSingleton<ISearchEngine, SearchEngine>();
 
             serviceCollection.AddSingleton<ServiceController>();
             serviceCollection.AddSingleton<IHttpListener, WebSocketSharpListener>();
             serviceCollection.AddSingleton<IHttpServer, HttpListenerHost>();
 
-            ImageProcessor = new ImageProcessor(LoggerFactory.CreateLogger<ImageProcessor>(), ServerConfigurationManager.ApplicationPaths, FileSystemManager, ImageEncoder, () => LibraryManager, () => MediaEncoder);
-            serviceCollection.AddSingleton(ImageProcessor);
-
-            TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
-            serviceCollection.AddSingleton(TVSeriesManager);
-
-            DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager);
-            serviceCollection.AddSingleton(DeviceManager);
-
-            MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, () => MediaEncoder);
-            serviceCollection.AddSingleton(MediaSourceManager);
-
-            SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, LocalizationManager);
-            serviceCollection.AddSingleton(SubtitleManager);
-
-            ProviderManager = new ProviderManager(HttpClient, SubtitleManager, ServerConfigurationManager, LibraryMonitor, LoggerFactory, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer);
-            serviceCollection.AddSingleton(ProviderManager);
-
-            DtoService = new DtoService(LoggerFactory, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ProviderManager, this, () => MediaSourceManager, () => LiveTvManager);
-            serviceCollection.AddSingleton(DtoService);
-
-            ChannelManager = new ChannelManager(
-                UserManager,
-                DtoService,
-                LibraryManager,
-                LoggerFactory.CreateLogger<ChannelManager>(),
-                ServerConfigurationManager,
-                FileSystemManager,
-                UserDataManager,
-                JsonSerializer,
-                ProviderManager);
-            serviceCollection.AddSingleton(ChannelManager);
-
-            SessionManager = new SessionManager(
-                LoggerFactory.CreateLogger<SessionManager>(),
-                UserDataManager,
-                LibraryManager,
-                UserManager,
-                musicManager,
-                DtoService,
-                ImageProcessor,
-                this,
-                AuthenticationRepository,
-                DeviceManager,
-                MediaSourceManager);
-            serviceCollection.AddSingleton(SessionManager);
-
-            serviceCollection.AddSingleton<IDlnaManager>(
-                new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LoggerFactory, JsonSerializer, this));
-
-            CollectionManager = new CollectionManager(LibraryManager, ApplicationPaths, LocalizationManager, FileSystemManager, LibraryMonitor, LoggerFactory, ProviderManager);
-            serviceCollection.AddSingleton(CollectionManager);
-
-            serviceCollection.AddSingleton(typeof(IPlaylistManager), typeof(PlaylistManager));
-
-            LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager);
-            serviceCollection.AddSingleton(LiveTvManager);
-
-            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
-            serviceCollection.AddSingleton(UserViewManager);
-
-            NotificationManager = new NotificationManager(
-                LoggerFactory.CreateLogger<NotificationManager>(),
-                UserManager,
-                ServerConfigurationManager);
-            serviceCollection.AddSingleton(NotificationManager);
-
-            serviceCollection.AddSingleton<IDeviceDiscovery>(new DeviceDiscovery(ServerConfigurationManager));
-
-            ChapterManager = new ChapterManager(ItemRepository);
-            serviceCollection.AddSingleton(ChapterManager);
-
-            EncodingManager = new MediaEncoder.EncodingManager(
-                LoggerFactory.CreateLogger<MediaEncoder.EncodingManager>(),
-                FileSystemManager,
-                MediaEncoder,
-                ChapterManager,
-                LibraryManager);
-            serviceCollection.AddSingleton(EncodingManager);
-
-            var activityLogRepo = GetActivityLogRepository();
-            serviceCollection.AddSingleton(activityLogRepo);
-            serviceCollection.AddSingleton<IActivityManager>(new ActivityManager(activityLogRepo, UserManager));
-
-            var authContext = new AuthorizationContext(AuthenticationRepository, UserManager);
-            serviceCollection.AddSingleton<IAuthorizationContext>(authContext);
-            serviceCollection.AddSingleton<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
-
-            AuthService = new AuthService(LoggerFactory.CreateLogger<AuthService>(), authContext, ServerConfigurationManager, SessionManager, NetworkManager);
-            serviceCollection.AddSingleton(AuthService);
-
-            SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(
-                LibraryManager,
-                LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(),
-                ApplicationPaths,
-                FileSystemManager,
-                MediaEncoder,
-                HttpClient,
-                MediaSourceManager);
-            serviceCollection.AddSingleton(SubtitleEncoder);
-
-            serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
-            serviceCollection.AddSingleton<EncodingHelper>();
+            serviceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
 
-            serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor));
+            serviceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
 
-            _displayPreferencesRepository.Initialize();
+            serviceCollection.AddSingleton<IDeviceManager, DeviceManager>();
 
-            var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger<SqliteUserDataRepository>(), ApplicationPaths);
+            serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
 
-            SetStaticProperties();
+            serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
+
+            serviceCollection.AddSingleton<IProviderManager, ProviderManager>();
+
+            // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
+            serviceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
+            serviceCollection.AddSingleton<IDtoService, DtoService>();
+
+            serviceCollection.AddSingleton<IChannelManager, ChannelManager>();
+
+            serviceCollection.AddSingleton<ISessionManager, SessionManager>();
+
+            serviceCollection.AddSingleton<IDlnaManager, DlnaManager>();
+
+            serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
 
-            ((UserManager)UserManager).Initialize();
+            serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
 
-            ((UserDataManager)UserDataManager).Repository = userDataRepo;
-            ItemRepository.Initialize(userDataRepo, UserManager);
-            ((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
+            serviceCollection.AddSingleton<LiveTvDtoService>();
+            serviceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
+
+            serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
+
+            serviceCollection.AddSingleton<INotificationManager, NotificationManager>();
+
+            serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
+
+            serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
+
+            serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
+
+            serviceCollection.AddSingleton<IActivityRepository, ActivityRepository>();
+            serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
+
+            serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
+            serviceCollection.AddSingleton<ISessionContext, SessionContext>();
+
+            serviceCollection.AddSingleton<IAuthService, AuthService>();
+
+            serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
+
+            serviceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
+            serviceCollection.AddSingleton<EncodingHelper>();
+
+            serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
         }
 
         /// <summary>
         /// Create services registered with the service container that need to be initialized at application startup.
         /// </summary>
-        public void InitializeServices()
+        /// <returns>A task representing the service initialization operation.</returns>
+        public async Task InitializeServices()
         {
-            HttpServer = Resolve<IHttpServer>();
+            var localizationManager = (LocalizationManager)Resolve<ILocalizationManager>();
+            await localizationManager.LoadAll().ConfigureAwait(false);
+
+            _mediaEncoder = Resolve<IMediaEncoder>();
+            _sessionManager = Resolve<ISessionManager>();
+            _httpServer = Resolve<IHttpServer>();
+            _httpClient = Resolve<IHttpClient>();
+
+            ((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
+            ((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
+            ((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
+            ((ActivityRepository)Resolve<IActivityRepository>()).Initialize();
+
+            SetStaticProperties();
+
+            var userManager = (UserManager)Resolve<IUserManager>();
+            userManager.Initialize();
+
+            var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
+            ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
+
+            FindParts();
         }
 
         public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths)
@@ -940,75 +768,38 @@ namespace Emby.Server.Implementations
             }
         }
 
-        /// <summary>
-        /// Gets the user repository.
-        /// </summary>
-        /// <returns><see cref="Task{SqliteUserRepository}" />.</returns>
-        private SqliteUserRepository GetUserRepository()
-        {
-            var repo = new SqliteUserRepository(
-                LoggerFactory.CreateLogger<SqliteUserRepository>(),
-                ApplicationPaths);
-
-            repo.Initialize();
-
-            return repo;
-        }
-
-        private IAuthenticationRepository GetAuthenticationRepository()
-        {
-            var repo = new AuthenticationRepository(LoggerFactory, ServerConfigurationManager);
-
-            repo.Initialize();
-
-            return repo;
-        }
-
-        private IActivityRepository GetActivityLogRepository()
-        {
-            var repo = new ActivityRepository(LoggerFactory.CreateLogger<ActivityRepository>(), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
-
-            repo.Initialize();
-
-            return repo;
-        }
-
         /// <summary>
         /// Dirty hacks.
         /// </summary>
         private void SetStaticProperties()
         {
-            ItemRepository.ImageProcessor = ImageProcessor;
-
             // For now there's no real way to inject these properly
-            BaseItem.Logger = LoggerFactory.CreateLogger("BaseItem");
+            BaseItem.Logger = Resolve<ILogger<BaseItem>>();
             BaseItem.ConfigurationManager = ServerConfigurationManager;
-            BaseItem.LibraryManager = LibraryManager;
-            BaseItem.ProviderManager = ProviderManager;
-            BaseItem.LocalizationManager = LocalizationManager;
-            BaseItem.ItemRepository = ItemRepository;
-            User.UserManager = UserManager;
-            BaseItem.FileSystem = FileSystemManager;
-            BaseItem.UserDataManager = UserDataManager;
-            BaseItem.ChannelManager = ChannelManager;
-            Video.LiveTvManager = LiveTvManager;
-            Folder.UserViewManager = UserViewManager;
-            UserView.TVSeriesManager = TVSeriesManager;
-            UserView.CollectionManager = CollectionManager;
-            BaseItem.MediaSourceManager = MediaSourceManager;
-            CollectionFolder.XmlSerializer = XmlSerializer;
-            CollectionFolder.JsonSerializer = JsonSerializer;
+            BaseItem.LibraryManager = Resolve<ILibraryManager>();
+            BaseItem.ProviderManager = Resolve<IProviderManager>();
+            BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
+            BaseItem.ItemRepository = Resolve<IItemRepository>();
+            User.UserManager = Resolve<IUserManager>();
+            BaseItem.FileSystem = _fileSystemManager;
+            BaseItem.UserDataManager = Resolve<IUserDataManager>();
+            BaseItem.ChannelManager = Resolve<IChannelManager>();
+            Video.LiveTvManager = Resolve<ILiveTvManager>();
+            Folder.UserViewManager = Resolve<IUserViewManager>();
+            UserView.TVSeriesManager = Resolve<ITVSeriesManager>();
+            UserView.CollectionManager = Resolve<ICollectionManager>();
+            BaseItem.MediaSourceManager = Resolve<IMediaSourceManager>();
+            CollectionFolder.XmlSerializer = _xmlSerializer;
+            CollectionFolder.JsonSerializer = Resolve<IJsonSerializer>();
             CollectionFolder.ApplicationHost = this;
-            AuthenticatedAttribute.AuthService = AuthService;
+            AuthenticatedAttribute.AuthService = Resolve<IAuthService>();
         }
 
         /// <summary>
-        /// Finds the parts.
+        /// Finds plugin components and register them with the appropriate services.
         /// </summary>
-        public void FindParts()
+        private void FindParts()
         {
-            InstallationManager = ServiceProvider.GetService<IInstallationManager>();
-
             if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
             {
                 ServerConfigurationManager.Configuration.IsPortAuthorized = true;
@@ -1021,34 +812,34 @@ namespace Emby.Server.Implementations
                         .Where(i => i != null)
                         .ToArray();
 
-            HttpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes());
+            _httpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes());
 
-            LibraryManager.AddParts(
+            Resolve<ILibraryManager>().AddParts(
                 GetExports<IResolverIgnoreRule>(),
                 GetExports<IItemResolver>(),
                 GetExports<IIntroProvider>(),
                 GetExports<IBaseItemComparer>(),
                 GetExports<ILibraryPostScanTask>());
 
-            ProviderManager.AddParts(
+            Resolve<IProviderManager>().AddParts(
                 GetExports<IImageProvider>(),
                 GetExports<IMetadataService>(),
                 GetExports<IMetadataProvider>(),
                 GetExports<IMetadataSaver>(),
                 GetExports<IExternalId>());
 
-            LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
+            Resolve<ILiveTvManager>().AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
 
-            SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
+            Resolve<ISubtitleManager>().AddParts(GetExports<ISubtitleProvider>());
 
-            ChannelManager.AddParts(GetExports<IChannel>());
+            Resolve<IChannelManager>().AddParts(GetExports<IChannel>());
 
-            MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
+            Resolve<IMediaSourceManager>().AddParts(GetExports<IMediaSourceProvider>());
 
-            NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
-            UserManager.AddParts(GetExports<IAuthenticationProvider>(), GetExports<IPasswordResetProvider>());
+            Resolve<INotificationManager>().AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
+            Resolve<IUserManager>().AddParts(GetExports<IAuthenticationProvider>(), GetExports<IPasswordResetProvider>());
 
-            IsoManager.AddParts(GetExports<IIsoMounter>());
+            Resolve<IIsoManager>().AddParts(GetExports<IIsoMounter>());
         }
 
         private IPlugin LoadPlugin(IPlugin plugin)
@@ -1155,16 +946,6 @@ namespace Emby.Server.Implementations
             });
         }
 
-        private CertificateInfo GetCertificateInfo(bool generateCertificate)
-        {
-            // Custom cert
-            return new CertificateInfo
-            {
-                Path = ServerConfigurationManager.Configuration.CertificatePath,
-                Password = ServerConfigurationManager.Configuration.CertificatePassword
-            };
-        }
-
         /// <summary>
         /// Called when [configuration updated].
         /// </summary>
@@ -1191,14 +972,13 @@ namespace Emby.Server.Implementations
                 }
             }
 
-            if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
+            if (!_httpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
             {
                 requiresRestart = true;
             }
 
             var currentCertPath = CertificateInfo?.Path;
-            var newCertInfo = GetCertificateInfo(false);
-            var newCertPath = newCertInfo?.Path;
+            var newCertPath = ServerConfigurationManager.Configuration.CertificatePath;
 
             if (!string.Equals(currentCertPath, newCertPath, StringComparison.OrdinalIgnoreCase))
             {
@@ -1251,7 +1031,7 @@ namespace Emby.Server.Implementations
             {
                 try
                 {
-                    await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
+                    await _sessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
                 }
                 catch (Exception ex)
                 {
@@ -1355,7 +1135,7 @@ namespace Emby.Server.Implementations
                 IsShuttingDown = IsShuttingDown,
                 Version = ApplicationVersionString,
                 WebSocketPortNumber = HttpPort,
-                CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
+                CompletedInstallations = Resolve<IInstallationManager>().CompletedInstallations.ToArray(),
                 Id = SystemId,
                 ProgramDataPath = ApplicationPaths.ProgramDataPath,
                 WebPath = ApplicationPaths.WebPath,
@@ -1375,14 +1155,14 @@ namespace Emby.Server.Implementations
                 ServerName = FriendlyName,
                 LocalAddress = localAddress,
                 SupportsLibraryMonitor = true,
-                EncoderLocation = MediaEncoder.EncoderLocation,
+                EncoderLocation = _mediaEncoder.EncoderLocation,
                 SystemArchitecture = RuntimeInformation.OSArchitecture,
-                PackageName = StartupOptions.PackageName
+                PackageName = _startupOptions.PackageName
             };
         }
 
         public IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo()
-            => NetworkManager.GetMacAddresses()
+            => _networkManager.GetMacAddresses()
                 .Select(i => new WakeOnLanInfo(i))
                 .ToList();
 
@@ -1494,7 +1274,7 @@ namespace Emby.Server.Implementations
 
             if (addresses.Count == 0)
             {
-                addresses.AddRange(NetworkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
+                addresses.AddRange(_networkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
             }
 
             var resultList = new List<IPAddress>();
@@ -1561,7 +1341,7 @@ namespace Emby.Server.Implementations
 
             try
             {
-                using (var response = await HttpClient.SendAsync(
+                using (var response = await _httpClient.SendAsync(
                     new HttpRequestOptions
                     {
                         Url = apiUrl,
@@ -1614,7 +1394,7 @@ namespace Emby.Server.Implementations
 
             try
             {
-                await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
+                await _sessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
             }
             catch (Exception ex)
             {
@@ -1735,14 +1515,8 @@ namespace Emby.Server.Implementations
                         Logger.LogError(ex, "Error disposing {Type}", part.GetType().Name);
                     }
                 }
-
-                _userRepository?.Dispose();
-                _displayPreferencesRepository?.Dispose();
             }
 
-            _userRepository = null;
-            _displayPreferencesRepository = null;
-
             _disposed = true;
         }
     }

+ 6 - 7
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -39,12 +39,11 @@ namespace Emby.Server.Implementations.Data
     {
         private const string ChaptersTableName = "Chapters2";
 
-        /// <summary>
-        /// The _app paths
-        /// </summary>
         private readonly IServerConfigurationManager _config;
         private readonly IServerApplicationHost _appHost;
         private readonly ILocalizationManager _localization;
+        // TODO: Remove this dependency. GetImageCacheTag() is the only method used and it can be converted to a static helper method
+        private readonly IImageProcessor _imageProcessor;
 
         private readonly TypeMapper _typeMapper;
         private readonly JsonSerializerOptions _jsonOptions;
@@ -71,7 +70,8 @@ namespace Emby.Server.Implementations.Data
             IServerConfigurationManager config,
             IServerApplicationHost appHost,
             ILogger<SqliteItemRepository> logger,
-            ILocalizationManager localization)
+            ILocalizationManager localization,
+            IImageProcessor imageProcessor)
             : base(logger)
         {
             if (config == null)
@@ -82,6 +82,7 @@ namespace Emby.Server.Implementations.Data
             _config = config;
             _appHost = appHost;
             _localization = localization;
+            _imageProcessor = imageProcessor;
 
             _typeMapper = new TypeMapper();
             _jsonOptions = JsonDefaults.GetOptions();
@@ -98,8 +99,6 @@ namespace Emby.Server.Implementations.Data
         /// <inheritdoc />
         protected override TempStoreMode TempStore => TempStoreMode.Memory;
 
-        public IImageProcessor ImageProcessor { get; set; }
-
         /// <summary>
         /// Opens the connection to the database
         /// </summary>
@@ -1991,7 +1990,7 @@ namespace Emby.Server.Implementations.Data
 
                 if (!string.IsNullOrEmpty(chapter.ImagePath))
                 {
-                    chapter.ImageTag = ImageProcessor.GetImageCacheTag(item, chapter);
+                    chapter.ImageTag = _imageProcessor.GetImageCacheTag(item, chapter);
                 }
             }
 

+ 3 - 3
Emby.Server.Implementations/Devices/DeviceManager.cs

@@ -38,10 +38,11 @@ namespace Emby.Server.Implementations.Devices
         private readonly IServerConfigurationManager _config;
         private readonly ILibraryManager _libraryManager;
         private readonly ILocalizationManager _localizationManager;
-
         private readonly IAuthenticationRepository _authRepo;
+        private readonly Dictionary<string, ClientCapabilities> _capabilitiesCache;
 
         public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
+
         public event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
 
         private readonly object _cameraUploadSyncLock = new object();
@@ -65,10 +66,9 @@ namespace Emby.Server.Implementations.Devices
             _libraryManager = libraryManager;
             _localizationManager = localizationManager;
             _authRepo = authRepo;
+            _capabilitiesCache = new Dictionary<string, ClientCapabilities>(StringComparer.OrdinalIgnoreCase);
         }
 
-
-        private Dictionary<string, ClientCapabilities> _capabilitiesCache = new Dictionary<string, ClientCapabilities>(StringComparer.OrdinalIgnoreCase);
         public void SaveCapabilities(string deviceId, ClientCapabilities capabilities)
         {
             var path = Path.Combine(GetDevicePath(deviceId), "capabilities.json");

+ 16 - 14
Emby.Server.Implementations/Dto/DtoService.cs

@@ -38,21 +38,23 @@ namespace Emby.Server.Implementations.Dto
         private readonly IProviderManager _providerManager;
 
         private readonly IApplicationHost _appHost;
-        private readonly Func<IMediaSourceManager> _mediaSourceManager;
-        private readonly Func<ILiveTvManager> _livetvManager;
+        private readonly IMediaSourceManager _mediaSourceManager;
+        private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
+
+        private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
 
         public DtoService(
-            ILoggerFactory loggerFactory,
+            ILogger<DtoService> logger,
             ILibraryManager libraryManager,
             IUserDataManager userDataRepository,
             IItemRepository itemRepo,
             IImageProcessor imageProcessor,
             IProviderManager providerManager,
             IApplicationHost appHost,
-            Func<IMediaSourceManager> mediaSourceManager,
-            Func<ILiveTvManager> livetvManager)
+            IMediaSourceManager mediaSourceManager,
+            Lazy<ILiveTvManager> livetvManagerFactory)
         {
-            _logger = loggerFactory.CreateLogger(nameof(DtoService));
+            _logger = logger;
             _libraryManager = libraryManager;
             _userDataRepository = userDataRepository;
             _itemRepo = itemRepo;
@@ -60,7 +62,7 @@ namespace Emby.Server.Implementations.Dto
             _providerManager = providerManager;
             _appHost = appHost;
             _mediaSourceManager = mediaSourceManager;
-            _livetvManager = livetvManager;
+            _livetvManagerFactory = livetvManagerFactory;
         }
 
         /// <summary>
@@ -125,12 +127,12 @@ namespace Emby.Server.Implementations.Dto
 
             if (programTuples.Count > 0)
             {
-                _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user).GetAwaiter().GetResult();
+                LivetvManager.AddInfoToProgramDto(programTuples, options.Fields, user).GetAwaiter().GetResult();
             }
 
             if (channelTuples.Count > 0)
             {
-                _livetvManager().AddChannelInfo(channelTuples, options, user);
+                LivetvManager.AddChannelInfo(channelTuples, options, user);
             }
 
             return returnItems;
@@ -142,12 +144,12 @@ namespace Emby.Server.Implementations.Dto
             if (item is LiveTvChannel tvChannel)
             {
                 var list = new List<(BaseItemDto, LiveTvChannel)>(1) { (dto, tvChannel) };
-                _livetvManager().AddChannelInfo(list, options, user);
+                LivetvManager.AddChannelInfo(list, options, user);
             }
             else if (item is LiveTvProgram)
             {
                 var list = new List<(BaseItem, BaseItemDto)>(1) { (item, dto) };
-                var task = _livetvManager().AddInfoToProgramDto(list, options.Fields, user);
+                var task = LivetvManager.AddInfoToProgramDto(list, options.Fields, user);
                 Task.WaitAll(task);
             }
 
@@ -223,7 +225,7 @@ namespace Emby.Server.Implementations.Dto
             if (item is IHasMediaSources
                 && options.ContainsField(ItemFields.MediaSources))
             {
-                dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(item, true, user).ToArray();
+                dto.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, true, user).ToArray();
 
                 NormalizeMediaSourceContainers(dto);
             }
@@ -254,7 +256,7 @@ namespace Emby.Server.Implementations.Dto
                 dto.Etag = item.GetEtag(user);
             }
 
-            var liveTvManager = _livetvManager();
+            var liveTvManager = LivetvManager;
             var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path);
             if (activeRecording != null)
             {
@@ -1045,7 +1047,7 @@ namespace Emby.Server.Implementations.Dto
                     }
                     else
                     {
-                        mediaStreams = _mediaSourceManager().GetStaticMediaSources(item, true)[0].MediaStreams.ToArray();
+                        mediaStreams = _mediaSourceManager.GetStaticMediaSources(item, true)[0].MediaStreams.ToArray();
                     }
 
                     dto.MediaStreams = mediaStreams;

+ 10 - 3
Emby.Server.Implementations/EntryPoints/StartupWizard.cs

@@ -16,17 +16,25 @@ namespace Emby.Server.Implementations.EntryPoints
         private readonly IServerApplicationHost _appHost;
         private readonly IConfiguration _appConfig;
         private readonly IServerConfigurationManager _config;
+        private readonly IStartupOptions _startupOptions;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="StartupWizard"/> class.
         /// </summary>
         /// <param name="appHost">The application host.</param>
+        /// <param name="appConfig">The application configuration.</param>
         /// <param name="config">The configuration manager.</param>
-        public StartupWizard(IServerApplicationHost appHost, IConfiguration appConfig, IServerConfigurationManager config)
+        /// <param name="startupOptions">The application startup options.</param>
+        public StartupWizard(
+            IServerApplicationHost appHost,
+            IConfiguration appConfig,
+            IServerConfigurationManager config,
+            IStartupOptions startupOptions)
         {
             _appHost = appHost;
             _appConfig = appConfig;
             _config = config;
+            _startupOptions = startupOptions;
         }
 
         /// <inheritdoc />
@@ -51,8 +59,7 @@ namespace Emby.Server.Implementations.EntryPoints
             }
 
             // Do nothing if the web app is configured to not run automatically
-            var options = ((ApplicationHost)_appHost).StartupOptions;
-            if (!_config.Configuration.AutoRunWebApp || options.NoAutoRunWebApp)
+            if (!_config.Configuration.AutoRunWebApp || _startupOptions.NoAutoRunWebApp)
             {
                 return;
             }

+ 5 - 4
Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs

@@ -6,6 +6,7 @@ using System.Linq;
 using System.Net;
 using System.Net.Http;
 using System.Threading.Tasks;
+using MediaBrowser.Common;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
@@ -24,7 +25,7 @@ namespace Emby.Server.Implementations.HttpClientManager
         private readonly ILogger _logger;
         private readonly IApplicationPaths _appPaths;
         private readonly IFileSystem _fileSystem;
-        private readonly Func<string> _defaultUserAgentFn;
+        private readonly IApplicationHost _appHost;
 
         /// <summary>
         /// Holds a dictionary of http clients by host.  Use GetHttpClient(host) to retrieve or create a client for web requests.
@@ -40,12 +41,12 @@ namespace Emby.Server.Implementations.HttpClientManager
             IApplicationPaths appPaths,
             ILogger<HttpClientManager> logger,
             IFileSystem fileSystem,
-            Func<string> defaultUserAgentFn)
+            IApplicationHost appHost)
         {
             _logger = logger ?? throw new ArgumentNullException(nameof(logger));
             _fileSystem = fileSystem;
             _appPaths = appPaths ?? throw new ArgumentNullException(nameof(appPaths));
-            _defaultUserAgentFn = defaultUserAgentFn;
+            _appHost = appHost;
         }
 
         /// <summary>
@@ -91,7 +92,7 @@ namespace Emby.Server.Implementations.HttpClientManager
             if (options.EnableDefaultUserAgent
                 && !request.Headers.TryGetValues(HeaderNames.UserAgent, out _))
             {
-                request.Headers.Add(HeaderNames.UserAgent, _defaultUserAgentFn());
+                request.Headers.Add(HeaderNames.UserAgent, _appHost.ApplicationUserAgent);
             }
 
             switch (options.DecompressionMethod)

+ 26 - 32
Emby.Server.Implementations/IO/LibraryMonitor.cs

@@ -17,6 +17,11 @@ namespace Emby.Server.Implementations.IO
 {
     public class LibraryMonitor : ILibraryMonitor
     {
+        private readonly ILogger _logger;
+        private readonly ILibraryManager _libraryManager;
+        private readonly IServerConfigurationManager _configurationManager;
+        private readonly IFileSystem _fileSystem;
+
         /// <summary>
         /// The file system watchers.
         /// </summary>
@@ -113,34 +118,23 @@ namespace Emby.Server.Implementations.IO
                 }
                 catch (Exception ex)
                 {
-                    Logger.LogError(ex, "Error in ReportFileSystemChanged for {path}", path);
+                    _logger.LogError(ex, "Error in ReportFileSystemChanged for {path}", path);
                 }
             }
         }
 
-        /// <summary>
-        /// Gets or sets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
-        private ILogger Logger { get; set; }
-
-        private ILibraryManager LibraryManager { get; set; }
-        private IServerConfigurationManager ConfigurationManager { get; set; }
-
-        private readonly IFileSystem _fileSystem;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
         /// </summary>
         public LibraryMonitor(
-            ILoggerFactory loggerFactory,
+            ILogger<LibraryMonitor> logger,
             ILibraryManager libraryManager,
             IServerConfigurationManager configurationManager,
             IFileSystem fileSystem)
         {
-            LibraryManager = libraryManager;
-            Logger = loggerFactory.CreateLogger(GetType().Name);
-            ConfigurationManager = configurationManager;
+            _libraryManager = libraryManager;
+            _logger = logger;
+            _configurationManager = configurationManager;
             _fileSystem = fileSystem;
         }
 
@@ -151,7 +145,7 @@ namespace Emby.Server.Implementations.IO
                 return false;
             }
 
-            var options = LibraryManager.GetLibraryOptions(item);
+            var options = _libraryManager.GetLibraryOptions(item);
 
             if (options != null)
             {
@@ -163,12 +157,12 @@ namespace Emby.Server.Implementations.IO
 
         public void Start()
         {
-            LibraryManager.ItemAdded += OnLibraryManagerItemAdded;
-            LibraryManager.ItemRemoved += OnLibraryManagerItemRemoved;
+            _libraryManager.ItemAdded += OnLibraryManagerItemAdded;
+            _libraryManager.ItemRemoved += OnLibraryManagerItemRemoved;
 
             var pathsToWatch = new List<string>();
 
-            var paths = LibraryManager
+            var paths = _libraryManager
                 .RootFolder
                 .Children
                 .Where(IsLibraryMonitorEnabled)
@@ -261,7 +255,7 @@ namespace Emby.Server.Implementations.IO
             if (!Directory.Exists(path))
             {
                 // Seeing a crash in the mono runtime due to an exception being thrown on a different thread
-                Logger.LogInformation("Skipping realtime monitor for {Path} because the path does not exist", path);
+                _logger.LogInformation("Skipping realtime monitor for {Path} because the path does not exist", path);
                 return;
             }
 
@@ -297,7 +291,7 @@ namespace Emby.Server.Implementations.IO
                     if (_fileSystemWatchers.TryAdd(path, newWatcher))
                     {
                         newWatcher.EnableRaisingEvents = true;
-                        Logger.LogInformation("Watching directory " + path);
+                        _logger.LogInformation("Watching directory " + path);
                     }
                     else
                     {
@@ -307,7 +301,7 @@ namespace Emby.Server.Implementations.IO
                 }
                 catch (Exception ex)
                 {
-                    Logger.LogError(ex, "Error watching path: {path}", path);
+                    _logger.LogError(ex, "Error watching path: {path}", path);
                 }
             });
         }
@@ -333,7 +327,7 @@ namespace Emby.Server.Implementations.IO
             {
                 using (watcher)
                 {
-                    Logger.LogInformation("Stopping directory watching for path {Path}", watcher.Path);
+                    _logger.LogInformation("Stopping directory watching for path {Path}", watcher.Path);
 
                     watcher.Created -= OnWatcherChanged;
                     watcher.Deleted -= OnWatcherChanged;
@@ -372,7 +366,7 @@ namespace Emby.Server.Implementations.IO
             var ex = e.GetException();
             var dw = (FileSystemWatcher)sender;
 
-            Logger.LogError(ex, "Error in Directory watcher for: {Path}", dw.Path);
+            _logger.LogError(ex, "Error in Directory watcher for: {Path}", dw.Path);
 
             DisposeWatcher(dw, true);
         }
@@ -390,7 +384,7 @@ namespace Emby.Server.Implementations.IO
             }
             catch (Exception ex)
             {
-                Logger.LogError(ex, "Exception in ReportFileSystemChanged. Path: {FullPath}", e.FullPath);
+                _logger.LogError(ex, "Exception in ReportFileSystemChanged. Path: {FullPath}", e.FullPath);
             }
         }
 
@@ -416,13 +410,13 @@ namespace Emby.Server.Implementations.IO
             {
                 if (_fileSystem.AreEqual(i, path))
                 {
-                    Logger.LogDebug("Ignoring change to {Path}", path);
+                    _logger.LogDebug("Ignoring change to {Path}", path);
                     return true;
                 }
 
                 if (_fileSystem.ContainsSubPath(i, path))
                 {
-                    Logger.LogDebug("Ignoring change to {Path}", path);
+                    _logger.LogDebug("Ignoring change to {Path}", path);
                     return true;
                 }
 
@@ -430,7 +424,7 @@ namespace Emby.Server.Implementations.IO
                 var parent = Path.GetDirectoryName(i);
                 if (!string.IsNullOrEmpty(parent) && _fileSystem.AreEqual(parent, path))
                 {
-                    Logger.LogDebug("Ignoring change to {Path}", path);
+                    _logger.LogDebug("Ignoring change to {Path}", path);
                     return true;
                 }
 
@@ -485,7 +479,7 @@ namespace Emby.Server.Implementations.IO
                     }
                 }
 
-                var newRefresher = new FileRefresher(path, ConfigurationManager, LibraryManager, Logger);
+                var newRefresher = new FileRefresher(path, _configurationManager, _libraryManager, _logger);
                 newRefresher.Completed += NewRefresher_Completed;
                 _activeRefreshers.Add(newRefresher);
             }
@@ -502,8 +496,8 @@ namespace Emby.Server.Implementations.IO
         /// </summary>
         public void Stop()
         {
-            LibraryManager.ItemAdded -= OnLibraryManagerItemAdded;
-            LibraryManager.ItemRemoved -= OnLibraryManagerItemRemoved;
+            _libraryManager.ItemAdded -= OnLibraryManagerItemAdded;
+            _libraryManager.ItemRemoved -= OnLibraryManagerItemRemoved;
 
             foreach (var watcher in _fileSystemWatchers.Values.ToList())
             {

+ 100 - 129
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -54,9 +54,29 @@ namespace Emby.Server.Implementations.Library
     /// </summary>
     public class LibraryManager : ILibraryManager
     {
+        private readonly ILogger _logger;
+        private readonly ITaskManager _taskManager;
+        private readonly IUserManager _userManager;
+        private readonly IUserDataManager _userDataRepository;
+        private readonly IServerConfigurationManager _configurationManager;
+        private readonly Lazy<ILibraryMonitor> _libraryMonitorFactory;
+        private readonly Lazy<IProviderManager> _providerManagerFactory;
+        private readonly Lazy<IUserViewManager> _userviewManagerFactory;
+        private readonly IServerApplicationHost _appHost;
+        private readonly IMediaEncoder _mediaEncoder;
+        private readonly IFileSystem _fileSystem;
+        private readonly IItemRepository _itemRepository;
+        private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
+
         private NamingOptions _namingOptions;
         private string[] _videoFileExtensions;
 
+        private ILibraryMonitor LibraryMonitor => _libraryMonitorFactory.Value;
+
+        private IProviderManager ProviderManager => _providerManagerFactory.Value;
+
+        private IUserViewManager UserViewManager => _userviewManagerFactory.Value;
+
         /// <summary>
         /// Gets or sets the postscan tasks.
         /// </summary>
@@ -89,12 +109,6 @@ namespace Emby.Server.Implementations.Library
         /// <value>The comparers.</value>
         private IBaseItemComparer[] Comparers { get; set; }
 
-        /// <summary>
-        /// Gets or sets the active item repository
-        /// </summary>
-        /// <value>The item repository.</value>
-        public IItemRepository ItemRepository { get; set; }
-
         /// <summary>
         /// Occurs when [item added].
         /// </summary>
@@ -110,90 +124,47 @@ namespace Emby.Server.Implementations.Library
         /// </summary>
         public event EventHandler<ItemChangeEventArgs> ItemRemoved;
 
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
-
-        /// <summary>
-        /// The _task manager
-        /// </summary>
-        private readonly ITaskManager _taskManager;
-
-        /// <summary>
-        /// The _user manager
-        /// </summary>
-        private readonly IUserManager _userManager;
-
-        /// <summary>
-        /// The _user data repository
-        /// </summary>
-        private readonly IUserDataManager _userDataRepository;
-
-        /// <summary>
-        /// Gets or sets the configuration manager.
-        /// </summary>
-        /// <value>The configuration manager.</value>
-        private IServerConfigurationManager ConfigurationManager { get; set; }
-
-        private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
-        private readonly Func<IProviderManager> _providerManagerFactory;
-        private readonly Func<IUserViewManager> _userviewManager;
         public bool IsScanRunning { get; private set; }
 
-        private IServerApplicationHost _appHost;
-        private readonly IMediaEncoder _mediaEncoder;
-
-        /// <summary>
-        /// The _library items cache
-        /// </summary>
-        private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
-
-        /// <summary>
-        /// Gets the library items cache.
-        /// </summary>
-        /// <value>The library items cache.</value>
-        private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache => _libraryItemsCache;
-
-        private readonly IFileSystem _fileSystem;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryManager" /> class.
         /// </summary>
         /// <param name="appHost">The application host</param>
-        /// <param name="loggerFactory">The logger factory.</param>
+        /// <param name="logger">The logger.</param>
         /// <param name="taskManager">The task manager.</param>
         /// <param name="userManager">The user manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         public LibraryManager(
             IServerApplicationHost appHost,
-            ILoggerFactory loggerFactory,
+            ILogger<LibraryManager> logger,
             ITaskManager taskManager,
             IUserManager userManager,
             IServerConfigurationManager configurationManager,
             IUserDataManager userDataRepository,
-            Func<ILibraryMonitor> libraryMonitorFactory,
+            Lazy<ILibraryMonitor> libraryMonitorFactory,
             IFileSystem fileSystem,
-            Func<IProviderManager> providerManagerFactory,
-            Func<IUserViewManager> userviewManager,
-            IMediaEncoder mediaEncoder)
+            Lazy<IProviderManager> providerManagerFactory,
+            Lazy<IUserViewManager> userviewManagerFactory,
+            IMediaEncoder mediaEncoder,
+            IItemRepository itemRepository)
         {
             _appHost = appHost;
-            _logger = loggerFactory.CreateLogger(nameof(LibraryManager));
+            _logger = logger;
             _taskManager = taskManager;
             _userManager = userManager;
-            ConfigurationManager = configurationManager;
+            _configurationManager = configurationManager;
             _userDataRepository = userDataRepository;
             _libraryMonitorFactory = libraryMonitorFactory;
             _fileSystem = fileSystem;
             _providerManagerFactory = providerManagerFactory;
-            _userviewManager = userviewManager;
+            _userviewManagerFactory = userviewManagerFactory;
             _mediaEncoder = mediaEncoder;
+            _itemRepository = itemRepository;
 
             _libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
 
-            ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
+            _configurationManager.ConfigurationUpdated += ConfigurationUpdated;
 
             RecordConfigurationValues(configurationManager.Configuration);
         }
@@ -272,7 +243,7 @@ namespace Emby.Server.Implementations.Library
         /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
         private void ConfigurationUpdated(object sender, EventArgs e)
         {
-            var config = ConfigurationManager.Configuration;
+            var config = _configurationManager.Configuration;
 
             var wizardChanged = config.IsStartupWizardCompleted != _wizardCompleted;
 
@@ -306,7 +277,7 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
+            _libraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
         }
 
         public void DeleteItem(BaseItem item, DeleteOptions options)
@@ -437,10 +408,10 @@ namespace Emby.Server.Implementations.Library
 
             item.SetParent(null);
 
-            ItemRepository.DeleteItem(item.Id);
+            _itemRepository.DeleteItem(item.Id);
             foreach (var child in children)
             {
-                ItemRepository.DeleteItem(child.Id);
+                _itemRepository.DeleteItem(child.Id);
             }
 
             _libraryItemsCache.TryRemove(item.Id, out BaseItem removed);
@@ -509,15 +480,15 @@ namespace Emby.Server.Implementations.Library
                 throw new ArgumentNullException(nameof(type));
             }
 
-            if (key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal))
+            if (key.StartsWith(_configurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal))
             {
                 // Try to normalize paths located underneath program-data in an attempt to make them more portable
-                key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length)
+                key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length)
                     .TrimStart(new[] { '/', '\\' })
                     .Replace("/", "\\");
             }
 
-            if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
+            if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds)
             {
                 key = key.ToLowerInvariant();
             }
@@ -550,7 +521,7 @@ namespace Emby.Server.Implementations.Library
                 collectionType = GetContentTypeOverride(fullPath, true);
             }
 
-            var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
+            var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, directoryService)
             {
                 Parent = parent,
                 Path = fullPath,
@@ -720,7 +691,7 @@ namespace Emby.Server.Implementations.Library
         /// <exception cref="InvalidOperationException">Cannot create the root folder until plugins have loaded.</exception>
         public AggregateFolder CreateRootFolder()
         {
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
+            var rootFolderPath = _configurationManager.ApplicationPaths.RootFolderPath;
 
             Directory.CreateDirectory(rootFolderPath);
 
@@ -734,7 +705,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             // Add in the plug-in folders
-            var path = Path.Combine(ConfigurationManager.ApplicationPaths.DataPath, "playlists");
+            var path = Path.Combine(_configurationManager.ApplicationPaths.DataPath, "playlists");
 
             Directory.CreateDirectory(path);
 
@@ -786,7 +757,7 @@ namespace Emby.Server.Implementations.Library
                 {
                     if (_userRootFolder == null)
                     {
-                        var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+                        var userRootPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
 
                         _logger.LogDebug("Creating userRootPath at {path}", userRootPath);
                         Directory.CreateDirectory(userRootPath);
@@ -980,7 +951,7 @@ namespace Emby.Server.Implementations.Library
               where T : BaseItem, new()
         {
             var path = getPathFn(name);
-            var forceCaseInsensitiveId = ConfigurationManager.Configuration.EnableNormalizedItemByNameIds;
+            var forceCaseInsensitiveId = _configurationManager.Configuration.EnableNormalizedItemByNameIds;
             return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
         }
 
@@ -994,7 +965,7 @@ namespace Emby.Server.Implementations.Library
         public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         {
             // Ensure the location is available.
-            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
+            Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath);
 
             return new PeopleValidator(this, _logger, _fileSystem).ValidatePeople(cancellationToken, progress);
         }
@@ -1031,7 +1002,7 @@ namespace Emby.Server.Implementations.Library
         public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
         {
             IsScanRunning = true;
-            _libraryMonitorFactory().Stop();
+            LibraryMonitor.Stop();
 
             try
             {
@@ -1039,7 +1010,7 @@ namespace Emby.Server.Implementations.Library
             }
             finally
             {
-                _libraryMonitorFactory().Start();
+                LibraryMonitor.Start();
                 IsScanRunning = false;
             }
         }
@@ -1148,7 +1119,7 @@ namespace Emby.Server.Implementations.Library
                 progress.Report(percent * 100);
             }
 
-            ItemRepository.UpdateInheritedValues(cancellationToken);
+            _itemRepository.UpdateInheritedValues(cancellationToken);
 
             progress.Report(100);
         }
@@ -1168,9 +1139,9 @@ namespace Emby.Server.Implementations.Library
             var topLibraryFolders = GetUserRootFolder().Children.ToList();
 
             _logger.LogDebug("Getting refreshQueue");
-            var refreshQueue = includeRefreshState ? _providerManagerFactory().GetRefreshQueue() : null;
+            var refreshQueue = includeRefreshState ? ProviderManager.GetRefreshQueue() : null;
 
-            return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath)
+            return _fileSystem.GetDirectoryPaths(_configurationManager.ApplicationPaths.DefaultUserViewsPath)
                 .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue))
                 .ToList();
         }
@@ -1245,7 +1216,7 @@ namespace Emby.Server.Implementations.Library
                 throw new ArgumentException("Guid can't be empty", nameof(id));
             }
 
-            if (LibraryItemsCache.TryGetValue(id, out BaseItem item))
+            if (_libraryItemsCache.TryGetValue(id, out BaseItem item))
             {
                 return item;
             }
@@ -1276,7 +1247,7 @@ namespace Emby.Server.Implementations.Library
                 AddUserToQuery(query, query.User, allowExternalContent);
             }
 
-            return ItemRepository.GetItemList(query);
+            return _itemRepository.GetItemList(query);
         }
 
         public List<BaseItem> GetItemList(InternalItemsQuery query)
@@ -1300,7 +1271,7 @@ namespace Emby.Server.Implementations.Library
                 AddUserToQuery(query, query.User);
             }
 
-            return ItemRepository.GetCount(query);
+            return _itemRepository.GetCount(query);
         }
 
         public List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
@@ -1315,7 +1286,7 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            return ItemRepository.GetItemList(query);
+            return _itemRepository.GetItemList(query);
         }
 
         public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
@@ -1327,12 +1298,12 @@ namespace Emby.Server.Implementations.Library
 
             if (query.EnableTotalRecordCount)
             {
-                return ItemRepository.GetItems(query);
+                return _itemRepository.GetItems(query);
             }
 
             return new QueryResult<BaseItem>
             {
-                Items = ItemRepository.GetItemList(query).ToArray()
+                Items = _itemRepository.GetItemList(query).ToArray()
             };
         }
 
@@ -1343,7 +1314,7 @@ namespace Emby.Server.Implementations.Library
                 AddUserToQuery(query, query.User);
             }
 
-            return ItemRepository.GetItemIdsList(query);
+            return _itemRepository.GetItemIdsList(query);
         }
 
         public QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query)
@@ -1354,7 +1325,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             SetTopParentOrAncestorIds(query);
-            return ItemRepository.GetStudios(query);
+            return _itemRepository.GetStudios(query);
         }
 
         public QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query)
@@ -1365,7 +1336,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             SetTopParentOrAncestorIds(query);
-            return ItemRepository.GetGenres(query);
+            return _itemRepository.GetGenres(query);
         }
 
         public QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query)
@@ -1376,7 +1347,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             SetTopParentOrAncestorIds(query);
-            return ItemRepository.GetMusicGenres(query);
+            return _itemRepository.GetMusicGenres(query);
         }
 
         public QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query)
@@ -1387,7 +1358,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             SetTopParentOrAncestorIds(query);
-            return ItemRepository.GetAllArtists(query);
+            return _itemRepository.GetAllArtists(query);
         }
 
         public QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query)
@@ -1398,7 +1369,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             SetTopParentOrAncestorIds(query);
-            return ItemRepository.GetArtists(query);
+            return _itemRepository.GetArtists(query);
         }
 
         private void SetTopParentOrAncestorIds(InternalItemsQuery query)
@@ -1439,7 +1410,7 @@ namespace Emby.Server.Implementations.Library
             }
 
             SetTopParentOrAncestorIds(query);
-            return ItemRepository.GetAlbumArtists(query);
+            return _itemRepository.GetAlbumArtists(query);
         }
 
         public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
@@ -1460,10 +1431,10 @@ namespace Emby.Server.Implementations.Library
 
             if (query.EnableTotalRecordCount)
             {
-                return ItemRepository.GetItems(query);
+                return _itemRepository.GetItems(query);
             }
 
-            var list = ItemRepository.GetItemList(query);
+            var list = _itemRepository.GetItemList(query);
 
             return new QueryResult<BaseItem>
             {
@@ -1509,7 +1480,7 @@ namespace Emby.Server.Implementations.Library
                 string.IsNullOrEmpty(query.SeriesPresentationUniqueKey) &&
                 query.ItemIds.Length == 0)
             {
-                var userViews = _userviewManager().GetUserViews(new UserViewQuery
+                var userViews = UserViewManager.GetUserViews(new UserViewQuery
                 {
                     UserId = user.Id,
                     IncludeHidden = true,
@@ -1809,7 +1780,7 @@ namespace Emby.Server.Implementations.Library
             // Don't iterate multiple times
             var itemsList = items.ToList();
 
-            ItemRepository.SaveItems(itemsList, cancellationToken);
+            _itemRepository.SaveItems(itemsList, cancellationToken);
 
             foreach (var item in itemsList)
             {
@@ -1846,7 +1817,7 @@ namespace Emby.Server.Implementations.Library
 
         public void UpdateImages(BaseItem item)
         {
-            ItemRepository.SaveImages(item);
+            _itemRepository.SaveImages(item);
 
             RegisterItem(item);
         }
@@ -1863,7 +1834,7 @@ namespace Emby.Server.Implementations.Library
             {
                 if (item.IsFileProtocol)
                 {
-                    _providerManagerFactory().SaveMetadata(item, updateReason);
+                    ProviderManager.SaveMetadata(item, updateReason);
                 }
 
                 item.DateLastSaved = DateTime.UtcNow;
@@ -1871,7 +1842,7 @@ namespace Emby.Server.Implementations.Library
                 RegisterItem(item);
             }
 
-            ItemRepository.SaveItems(itemsList, cancellationToken);
+            _itemRepository.SaveItems(itemsList, cancellationToken);
 
             if (ItemUpdated != null)
             {
@@ -1947,7 +1918,7 @@ namespace Emby.Server.Implementations.Library
         /// <returns>BaseItem.</returns>
         public BaseItem RetrieveItem(Guid id)
         {
-            return ItemRepository.RetrieveItem(id);
+            return _itemRepository.RetrieveItem(id);
         }
 
         public List<Folder> GetCollectionFolders(BaseItem item)
@@ -2066,7 +2037,7 @@ namespace Emby.Server.Implementations.Library
 
         private string GetContentTypeOverride(string path, bool inherit)
         {
-            var nameValuePair = ConfigurationManager.Configuration.ContentTypes
+            var nameValuePair = _configurationManager.Configuration.ContentTypes
                                     .FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path)
                                                          || (inherit && !string.IsNullOrEmpty(i.Name)
                                                                      && _fileSystem.ContainsSubPath(i.Name, path)));
@@ -2115,7 +2086,7 @@ namespace Emby.Server.Implementations.Library
             string sortName)
         {
             var path = Path.Combine(
-                ConfigurationManager.ApplicationPaths.InternalMetadataPath,
+                _configurationManager.ApplicationPaths.InternalMetadataPath,
                 "views",
                 _fileSystem.GetValidFilename(viewType));
 
@@ -2147,7 +2118,7 @@ namespace Emby.Server.Implementations.Library
             if (refresh)
             {
                 item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
-                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
+                ProviderManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
             }
 
             return item;
@@ -2165,7 +2136,7 @@ namespace Emby.Server.Implementations.Library
 
             var id = GetNewItemId(idValues, typeof(UserView));
 
-            var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
+            var path = Path.Combine(_configurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
 
             var item = GetItemById(id) as UserView;
 
@@ -2202,7 +2173,7 @@ namespace Emby.Server.Implementations.Library
 
             if (refresh)
             {
-                _providerManagerFactory().QueueRefresh(
+                ProviderManager.QueueRefresh(
                     item.Id,
                     new MetadataRefreshOptions(new DirectoryService(_fileSystem))
                     {
@@ -2269,7 +2240,7 @@ namespace Emby.Server.Implementations.Library
 
             if (refresh)
             {
-                _providerManagerFactory().QueueRefresh(
+                ProviderManager.QueueRefresh(
                     item.Id,
                     new MetadataRefreshOptions(new DirectoryService(_fileSystem))
                     {
@@ -2303,7 +2274,7 @@ namespace Emby.Server.Implementations.Library
 
             var id = GetNewItemId(idValues, typeof(UserView));
 
-            var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
+            var path = Path.Combine(_configurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
 
             var item = GetItemById(id) as UserView;
 
@@ -2346,7 +2317,7 @@ namespace Emby.Server.Implementations.Library
 
             if (refresh)
             {
-                _providerManagerFactory().QueueRefresh(
+                ProviderManager.QueueRefresh(
                     item.Id,
                     new MetadataRefreshOptions(new DirectoryService(_fileSystem))
                     {
@@ -2675,8 +2646,8 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            var metadataPath = ConfigurationManager.Configuration.MetadataPath;
-            var metadataNetworkPath = ConfigurationManager.Configuration.MetadataNetworkPath;
+            var metadataPath = _configurationManager.Configuration.MetadataPath;
+            var metadataNetworkPath = _configurationManager.Configuration.MetadataNetworkPath;
 
             if (!string.IsNullOrWhiteSpace(metadataPath) && !string.IsNullOrWhiteSpace(metadataNetworkPath))
             {
@@ -2687,7 +2658,7 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
+            foreach (var map in _configurationManager.Configuration.PathSubstitutions)
             {
                 if (!string.IsNullOrWhiteSpace(map.From))
                 {
@@ -2756,7 +2727,7 @@ namespace Emby.Server.Implementations.Library
 
         public List<PersonInfo> GetPeople(InternalPeopleQuery query)
         {
-            return ItemRepository.GetPeople(query);
+            return _itemRepository.GetPeople(query);
         }
 
         public List<PersonInfo> GetPeople(BaseItem item)
@@ -2779,7 +2750,7 @@ namespace Emby.Server.Implementations.Library
 
         public List<Person> GetPeopleItems(InternalPeopleQuery query)
         {
-            return ItemRepository.GetPeopleNames(query).Select(i =>
+            return _itemRepository.GetPeopleNames(query).Select(i =>
             {
                 try
                 {
@@ -2796,7 +2767,7 @@ namespace Emby.Server.Implementations.Library
 
         public List<string> GetPeopleNames(InternalPeopleQuery query)
         {
-            return ItemRepository.GetPeopleNames(query);
+            return _itemRepository.GetPeopleNames(query);
         }
 
         public void UpdatePeople(BaseItem item, List<PersonInfo> people)
@@ -2806,7 +2777,7 @@ namespace Emby.Server.Implementations.Library
                 return;
             }
 
-            ItemRepository.UpdatePeople(item.Id, people);
+            _itemRepository.UpdatePeople(item.Id, people);
         }
 
         public async Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex)
@@ -2817,7 +2788,7 @@ namespace Emby.Server.Implementations.Library
                 {
                     _logger.LogDebug("ConvertImageToLocal item {0} - image url: {1}", item.Id, url);
 
-                    await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
+                    await ProviderManager.SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
 
                     item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
 
@@ -2850,7 +2821,7 @@ namespace Emby.Server.Implementations.Library
 
             name = _fileSystem.GetValidFilename(name);
 
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+            var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
 
             var virtualFolderPath = Path.Combine(rootFolderPath, name);
             while (Directory.Exists(virtualFolderPath))
@@ -2869,7 +2840,7 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            _libraryMonitorFactory().Stop();
+            LibraryMonitor.Stop();
 
             try
             {
@@ -2904,7 +2875,7 @@ namespace Emby.Server.Implementations.Library
                 {
                     // Need to add a delay here or directory watchers may still pick up the changes
                     await Task.Delay(1000).ConfigureAwait(false);
-                    _libraryMonitorFactory().Start();
+                    LibraryMonitor.Start();
                 }
             }
         }
@@ -2964,7 +2935,7 @@ namespace Emby.Server.Implementations.Library
                 throw new FileNotFoundException("The network path does not exist.");
             }
 
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+            var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
             var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
 
             var shortcutFilename = Path.GetFileNameWithoutExtension(path);
@@ -3007,7 +2978,7 @@ namespace Emby.Server.Implementations.Library
                 throw new FileNotFoundException("The network path does not exist.");
             }
 
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+            var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
             var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
 
             var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
@@ -3060,7 +3031,7 @@ namespace Emby.Server.Implementations.Library
                 throw new ArgumentNullException(nameof(name));
             }
 
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+            var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
 
             var path = Path.Combine(rootFolderPath, name);
 
@@ -3069,7 +3040,7 @@ namespace Emby.Server.Implementations.Library
                 throw new FileNotFoundException("The media folder does not exist");
             }
 
-            _libraryMonitorFactory().Stop();
+            LibraryMonitor.Stop();
 
             try
             {
@@ -3089,7 +3060,7 @@ namespace Emby.Server.Implementations.Library
                 {
                     // Need to add a delay here or directory watchers may still pick up the changes
                     await Task.Delay(1000).ConfigureAwait(false);
-                    _libraryMonitorFactory().Start();
+                    LibraryMonitor.Start();
                 }
             }
         }
@@ -3103,7 +3074,7 @@ namespace Emby.Server.Implementations.Library
 
             var removeList = new List<NameValuePair>();
 
-            foreach (var contentType in ConfigurationManager.Configuration.ContentTypes)
+            foreach (var contentType in _configurationManager.Configuration.ContentTypes)
             {
                 if (string.IsNullOrWhiteSpace(contentType.Name))
                 {
@@ -3118,11 +3089,11 @@ namespace Emby.Server.Implementations.Library
 
             if (removeList.Count > 0)
             {
-                ConfigurationManager.Configuration.ContentTypes = ConfigurationManager.Configuration.ContentTypes
+                _configurationManager.Configuration.ContentTypes = _configurationManager.Configuration.ContentTypes
                     .Except(removeList)
-                        .ToArray();
+                    .ToArray();
 
-                ConfigurationManager.SaveConfiguration();
+                _configurationManager.SaveConfiguration();
             }
         }
 
@@ -3133,7 +3104,7 @@ namespace Emby.Server.Implementations.Library
                 throw new ArgumentNullException(nameof(mediaPath));
             }
 
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+            var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
             var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
 
             if (!Directory.Exists(virtualFolderPath))

+ 11 - 11
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -33,13 +33,13 @@ namespace Emby.Server.Implementations.Library
         private readonly ILibraryManager _libraryManager;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IFileSystem _fileSystem;
-
-        private IMediaSourceProvider[] _providers;
         private readonly ILogger _logger;
         private readonly IUserDataManager _userDataManager;
-        private readonly Func<IMediaEncoder> _mediaEncoder;
-        private ILocalizationManager _localizationManager;
-        private IApplicationPaths _appPaths;
+        private readonly IMediaEncoder _mediaEncoder;
+        private readonly ILocalizationManager _localizationManager;
+        private readonly IApplicationPaths _appPaths;
+
+        private IMediaSourceProvider[] _providers;
 
         public MediaSourceManager(
             IItemRepository itemRepo,
@@ -47,16 +47,16 @@ namespace Emby.Server.Implementations.Library
             ILocalizationManager localizationManager,
             IUserManager userManager,
             ILibraryManager libraryManager,
-            ILoggerFactory loggerFactory,
+            ILogger<MediaSourceManager> logger,
             IJsonSerializer jsonSerializer,
             IFileSystem fileSystem,
             IUserDataManager userDataManager,
-            Func<IMediaEncoder> mediaEncoder)
+            IMediaEncoder mediaEncoder)
         {
             _itemRepo = itemRepo;
             _userManager = userManager;
             _libraryManager = libraryManager;
-            _logger = loggerFactory.CreateLogger(nameof(MediaSourceManager));
+            _logger = logger;
             _jsonSerializer = jsonSerializer;
             _fileSystem = fileSystem;
             _userDataManager = userDataManager;
@@ -496,7 +496,7 @@ namespace Emby.Server.Implementations.Library
                     // hack - these two values were taken from LiveTVMediaSourceProvider
                     string cacheKey = request.OpenToken;
 
-                    await new LiveStreamHelper(_mediaEncoder(), _logger, _jsonSerializer, _appPaths)
+                    await new LiveStreamHelper(_mediaEncoder, _logger, _jsonSerializer, _appPaths)
                         .AddMediaInfoWithProbe(mediaSource, isAudio, cacheKey, true, cancellationToken)
                         .ConfigureAwait(false);
                 }
@@ -621,7 +621,7 @@ namespace Emby.Server.Implementations.Library
 
             if (liveStreamInfo is IDirectStreamProvider)
             {
-                var info = await _mediaEncoder().GetMediaInfo(new MediaInfoRequest
+                var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
                 {
                     MediaSource = mediaSource,
                     ExtractChapters = false,
@@ -674,7 +674,7 @@ namespace Emby.Server.Implementations.Library
                     mediaSource.AnalyzeDurationMs = 3000;
                 }
 
-                mediaInfo = await _mediaEncoder().GetMediaInfo(new MediaInfoRequest
+                mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
                 {
                     MediaSource = mediaSource,
                     MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,

+ 3 - 4
Emby.Server.Implementations/Library/SearchEngine.cs

@@ -17,16 +17,15 @@ namespace Emby.Server.Implementations.Library
 {
     public class SearchEngine : ISearchEngine
     {
+        private readonly ILogger _logger;
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
-        private readonly ILogger _logger;
 
-        public SearchEngine(ILoggerFactory loggerFactory, ILibraryManager libraryManager, IUserManager userManager)
+        public SearchEngine(ILogger<SearchEngine> logger, ILibraryManager libraryManager, IUserManager userManager)
         {
+            _logger = logger;
             _libraryManager = libraryManager;
             _userManager = userManager;
-
-            _logger = loggerFactory.CreateLogger("SearchEngine");
         }
 
         public QueryResult<SearchHintInfo> GetSearchHints(SearchQuery query)

+ 18 - 19
Emby.Server.Implementations/Library/UserDataManager.cs

@@ -28,25 +28,24 @@ namespace Emby.Server.Implementations.Library
 
         private readonly ILogger _logger;
         private readonly IServerConfigurationManager _config;
-
-        private Func<IUserManager> _userManager;
-
-        public UserDataManager(ILoggerFactory loggerFactory, IServerConfigurationManager config, Func<IUserManager> userManager)
+        private readonly IUserManager _userManager;
+        private readonly IUserDataRepository _repository;
+
+        public UserDataManager(
+            ILogger<UserDataManager> logger,
+            IServerConfigurationManager config,
+            IUserManager userManager,
+            IUserDataRepository repository)
         {
+            _logger = logger;
             _config = config;
-            _logger = loggerFactory.CreateLogger(GetType().Name);
             _userManager = userManager;
+            _repository = repository;
         }
 
-        /// <summary>
-        /// Gets or sets the repository.
-        /// </summary>
-        /// <value>The repository.</value>
-        public IUserDataRepository Repository { get; set; }
-
         public void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
         {
-            var user = _userManager().GetUserById(userId);
+            var user = _userManager.GetUserById(userId);
 
             SaveUserData(user, item, userData, reason, cancellationToken);
         }
@@ -71,7 +70,7 @@ namespace Emby.Server.Implementations.Library
 
             foreach (var key in keys)
             {
-                Repository.SaveUserData(userId, key, userData, cancellationToken);
+                _repository.SaveUserData(userId, key, userData, cancellationToken);
             }
 
             var cacheKey = GetCacheKey(userId, item.Id);
@@ -96,9 +95,9 @@ namespace Emby.Server.Implementations.Library
         /// <returns></returns>
         public void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken)
         {
-            var user = _userManager().GetUserById(userId);
+            var user = _userManager.GetUserById(userId);
 
-            Repository.SaveAllUserData(user.InternalId, userData, cancellationToken);
+            _repository.SaveAllUserData(user.InternalId, userData, cancellationToken);
         }
 
         /// <summary>
@@ -108,14 +107,14 @@ namespace Emby.Server.Implementations.Library
         /// <returns></returns>
         public List<UserItemData> GetAllUserData(Guid userId)
         {
-            var user = _userManager().GetUserById(userId);
+            var user = _userManager.GetUserById(userId);
 
-            return Repository.GetAllUserData(user.InternalId);
+            return _repository.GetAllUserData(user.InternalId);
         }
 
         public UserItemData GetUserData(Guid userId, Guid itemId, List<string> keys)
         {
-            var user = _userManager().GetUserById(userId);
+            var user = _userManager.GetUserById(userId);
 
             return GetUserData(user, itemId, keys);
         }
@@ -131,7 +130,7 @@ namespace Emby.Server.Implementations.Library
 
         private UserItemData GetUserDataInternal(long internalUserId, List<string> keys)
         {
-            var userData = Repository.GetUserData(internalUserId, keys);
+            var userData = _repository.GetUserData(internalUserId, keys);
 
             if (userData != null)
             {

+ 10 - 16
Emby.Server.Implementations/Library/UserManager.cs

@@ -44,22 +44,14 @@ namespace Emby.Server.Implementations.Library
     {
         private readonly object _policySyncLock = new object();
         private readonly object _configSyncLock = new object();
-        /// <summary>
-        /// The logger.
-        /// </summary>
-        private readonly ILogger _logger;
 
-        /// <summary>
-        /// Gets the active user repository.
-        /// </summary>
-        /// <value>The user repository.</value>
+        private readonly ILogger _logger;
         private readonly IUserRepository _userRepository;
         private readonly IXmlSerializer _xmlSerializer;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly INetworkManager _networkManager;
-
-        private readonly Func<IImageProcessor> _imageProcessorFactory;
-        private readonly Func<IDtoService> _dtoServiceFactory;
+        private readonly IImageProcessor _imageProcessor;
+        private readonly Lazy<IDtoService> _dtoServiceFactory;
         private readonly IServerApplicationHost _appHost;
         private readonly IFileSystem _fileSystem;
         private readonly ICryptoProvider _cryptoProvider;
@@ -74,13 +66,15 @@ namespace Emby.Server.Implementations.Library
         private IPasswordResetProvider[] _passwordResetProviders;
         private DefaultPasswordResetProvider _defaultPasswordResetProvider;
 
+        private IDtoService DtoService => _dtoServiceFactory.Value;
+
         public UserManager(
             ILogger<UserManager> logger,
             IUserRepository userRepository,
             IXmlSerializer xmlSerializer,
             INetworkManager networkManager,
-            Func<IImageProcessor> imageProcessorFactory,
-            Func<IDtoService> dtoServiceFactory,
+            IImageProcessor imageProcessor,
+            Lazy<IDtoService> dtoServiceFactory,
             IServerApplicationHost appHost,
             IJsonSerializer jsonSerializer,
             IFileSystem fileSystem,
@@ -90,7 +84,7 @@ namespace Emby.Server.Implementations.Library
             _userRepository = userRepository;
             _xmlSerializer = xmlSerializer;
             _networkManager = networkManager;
-            _imageProcessorFactory = imageProcessorFactory;
+            _imageProcessor = imageProcessor;
             _dtoServiceFactory = dtoServiceFactory;
             _appHost = appHost;
             _jsonSerializer = jsonSerializer;
@@ -605,7 +599,7 @@ namespace Emby.Server.Implementations.Library
 
                 try
                 {
-                    _dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user);
+                    DtoService.AttachPrimaryImageAspectRatio(dto, user);
                 }
                 catch (Exception ex)
                 {
@@ -630,7 +624,7 @@ namespace Emby.Server.Implementations.Library
         {
             try
             {
-                return _imageProcessorFactory().GetImageCacheTag(item, image);
+                return _imageProcessor.GetImageCacheTag(item, image);
             }
             catch (Exception ex)
             {

+ 0 - 1
Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -28,7 +28,6 @@ namespace Emby.Server.Implementations.LiveTv
 
         private readonly ILogger _logger;
         private readonly IImageProcessor _imageProcessor;
-
         private readonly IDtoService _dtoService;
         private readonly IApplicationHost _appHost;
         private readonly ILibraryManager _libraryManager;

+ 10 - 15
Emby.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -49,29 +49,24 @@ namespace Emby.Server.Implementations.LiveTv
         private readonly ILogger _logger;
         private readonly IItemRepository _itemRepo;
         private readonly IUserManager _userManager;
+        private readonly IDtoService _dtoService;
         private readonly IUserDataManager _userDataManager;
         private readonly ILibraryManager _libraryManager;
         private readonly ITaskManager _taskManager;
-        private readonly IJsonSerializer _jsonSerializer;
-        private readonly Func<IChannelManager> _channelManager;
-
-        private readonly IDtoService _dtoService;
         private readonly ILocalizationManager _localization;
-
+        private readonly IJsonSerializer _jsonSerializer;
+        private readonly IFileSystem _fileSystem;
+        private readonly IChannelManager _channelManager;
         private readonly LiveTvDtoService _tvDtoService;
 
         private ILiveTvService[] _services = Array.Empty<ILiveTvService>();
-
         private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
         private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
-        private readonly IFileSystem _fileSystem;
 
         public LiveTvManager(
-            IServerApplicationHost appHost,
             IServerConfigurationManager config,
-            ILoggerFactory loggerFactory,
+            ILogger<LiveTvManager> logger,
             IItemRepository itemRepo,
-            IImageProcessor imageProcessor,
             IUserDataManager userDataManager,
             IDtoService dtoService,
             IUserManager userManager,
@@ -80,10 +75,11 @@ namespace Emby.Server.Implementations.LiveTv
             ILocalizationManager localization,
             IJsonSerializer jsonSerializer,
             IFileSystem fileSystem,
-            Func<IChannelManager> channelManager)
+            IChannelManager channelManager,
+            LiveTvDtoService liveTvDtoService)
         {
             _config = config;
-            _logger = loggerFactory.CreateLogger(nameof(LiveTvManager));
+            _logger = logger;
             _itemRepo = itemRepo;
             _userManager = userManager;
             _libraryManager = libraryManager;
@@ -94,8 +90,7 @@ namespace Emby.Server.Implementations.LiveTv
             _dtoService = dtoService;
             _userDataManager = userDataManager;
             _channelManager = channelManager;
-
-            _tvDtoService = new LiveTvDtoService(dtoService, imageProcessor, loggerFactory.CreateLogger<LiveTvDtoService>(), appHost, _libraryManager);
+            _tvDtoService = liveTvDtoService;
         }
 
         public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
@@ -2496,7 +2491,7 @@ namespace Emby.Server.Implementations.LiveTv
                 .OrderBy(i => i.SortName)
                 .ToList();
 
-            folders.AddRange(_channelManager().GetChannelsInternal(new MediaBrowser.Model.Channels.ChannelQuery
+            folders.AddRange(_channelManager.GetChannelsInternal(new MediaBrowser.Model.Channels.ChannelQuery
             {
                 UserId = user.Id,
                 IsRecordingsFolder = true,

+ 0 - 3
Emby.Server.Implementations/Localization/LocalizationManager.cs

@@ -23,9 +23,6 @@ namespace Emby.Server.Implementations.Localization
         private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
         private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
 
-        /// <summary>
-        /// The _configuration manager.
-        /// </summary>
         private readonly IServerConfigurationManager _configurationManager;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly ILogger _logger;

+ 3 - 17
Emby.Server.Implementations/ScheduledTasks/TaskManager.cs

@@ -32,22 +32,8 @@ namespace Emby.Server.Implementations.ScheduledTasks
         private readonly ConcurrentQueue<Tuple<Type, TaskOptions>> _taskQueue =
             new ConcurrentQueue<Tuple<Type, TaskOptions>>();
 
-        /// <summary>
-        /// Gets or sets the json serializer.
-        /// </summary>
-        /// <value>The json serializer.</value>
         private readonly IJsonSerializer _jsonSerializer;
-
-        /// <summary>
-        /// Gets or sets the application paths.
-        /// </summary>
-        /// <value>The application paths.</value>
         private readonly IApplicationPaths _applicationPaths;
-
-        /// <summary>
-        /// Gets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
 
@@ -56,17 +42,17 @@ namespace Emby.Server.Implementations.ScheduledTasks
         /// </summary>
         /// <param name="applicationPaths">The application paths.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="loggerFactory">The logger factory.</param>
+        /// <param name="logger">The logger.</param>
         /// <param name="fileSystem">The filesystem manager.</param>
         public TaskManager(
             IApplicationPaths applicationPaths,
             IJsonSerializer jsonSerializer,
-            ILoggerFactory loggerFactory,
+            ILogger<TaskManager> logger,
             IFileSystem fileSystem)
         {
             _applicationPaths = applicationPaths;
             _jsonSerializer = jsonSerializer;
-            _logger = loggerFactory.CreateLogger(nameof(TaskManager));
+            _logger = logger;
             _fileSystem = fileSystem;
 
             ScheduledTasks = Array.Empty<IScheduledTaskWorker>();

+ 2 - 2
Emby.Server.Implementations/Security/AuthenticationRepository.cs

@@ -15,8 +15,8 @@ namespace Emby.Server.Implementations.Security
 {
     public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository
     {
-        public AuthenticationRepository(ILoggerFactory loggerFactory, IServerConfigurationManager config)
-            : base(loggerFactory.CreateLogger(nameof(AuthenticationRepository)))
+        public AuthenticationRepository(ILogger<AuthenticationRepository> logger, IServerConfigurationManager config)
+            : base(logger)
         {
             DbFilePath = Path.Combine(config.ApplicationPaths.DataPath, "authentication.db");
         }

+ 13 - 4
Jellyfin.Drawing.Skia/SkiaEncoder.cs

@@ -78,12 +78,21 @@ namespace Jellyfin.Drawing.Skia
             => new HashSet<ImageFormat>() { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png };
 
         /// <summary>
-        /// Test to determine if the native lib is available.
+        /// Check if the native lib is available.
         /// </summary>
-        public static void TestSkia()
+        /// <returns>True if the native lib is available, otherwise false.</returns>
+        public static bool IsNativeLibAvailable()
         {
-            // test an operation that requires the native library
-            SKPMColor.PreMultiply(SKColors.Black);
+            try
+            {
+                // test an operation that requires the native library
+                SKPMColor.PreMultiply(SKColors.Black);
+                return true;
+            }
+            catch (Exception)
+            {
+                return false;
+            }
         }
 
         private static bool IsTransparent(SKColor color)

+ 22 - 5
Jellyfin.Server/CoreAppHost.cs

@@ -1,9 +1,13 @@
+using System;
 using System.Collections.Generic;
 using System.Reflection;
+using Emby.Drawing;
 using Emby.Server.Implementations;
+using Jellyfin.Drawing.Skia;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Model.IO;
+using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 
 namespace Jellyfin.Server
@@ -20,27 +24,40 @@ namespace Jellyfin.Server
         /// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param>
         /// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
         /// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
-        /// <param name="imageEncoder">The <see cref="IImageEncoder" /> to be used by the <see cref="CoreAppHost" />.</param>
         /// <param name="networkManager">The <see cref="INetworkManager" /> to be used by the <see cref="CoreAppHost" />.</param>
         public CoreAppHost(
             ServerApplicationPaths applicationPaths,
             ILoggerFactory loggerFactory,
             StartupOptions options,
             IFileSystem fileSystem,
-            IImageEncoder imageEncoder,
             INetworkManager networkManager)
             : base(
                 applicationPaths,
                 loggerFactory,
                 options,
                 fileSystem,
-                imageEncoder,
                 networkManager)
         {
         }
 
-        /// <inheritdoc />
-        public override bool CanSelfRestart => StartupOptions.RestartPath != null;
+        /// <inheritdoc/>
+        protected override void RegisterServices(IServiceCollection serviceCollection)
+        {
+            // Register an image encoder
+            bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable();
+            Type imageEncoderType = useSkiaEncoder
+                ? typeof(SkiaEncoder)
+                : typeof(NullImageEncoder);
+            serviceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
+
+            // Log a warning if the Skia encoder could not be used
+            if (!useSkiaEncoder)
+            {
+                Logger.LogWarning($"Skia not available. Will fallback to {nameof(NullImageEncoder)}.");
+            }
+
+            base.RegisterServices(serviceCollection);
+        }
 
         /// <inheritdoc />
         protected override void RestartInternal() => Program.Restart();

+ 2 - 23
Jellyfin.Server/Program.cs

@@ -184,7 +184,6 @@ namespace Jellyfin.Server
                 _loggerFactory,
                 options,
                 new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
-                GetImageEncoder(appPaths),
                 new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()));
 
             try
@@ -204,14 +203,13 @@ namespace Jellyfin.Server
                 }
 
                 ServiceCollection serviceCollection = new ServiceCollection();
-                await appHost.InitAsync(serviceCollection, startupConfig).ConfigureAwait(false);
+                appHost.Init(serviceCollection);
 
                 var webHost = CreateWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
 
                 // Re-use the web host service provider in the app host since ASP.NET doesn't allow a custom service collection.
                 appHost.ServiceProvider = webHost.Services;
-                appHost.InitializeServices();
-                appHost.FindParts();
+                await appHost.InitializeServices().ConfigureAwait(false);
                 Migrations.MigrationRunner.Run(appHost, _loggerFactory);
 
                 try
@@ -571,25 +569,6 @@ namespace Jellyfin.Server
             }
         }
 
-        private static IImageEncoder GetImageEncoder(IApplicationPaths appPaths)
-        {
-            try
-            {
-                // Test if the native lib is available
-                SkiaEncoder.TestSkia();
-
-                return new SkiaEncoder(
-                    _loggerFactory.CreateLogger<SkiaEncoder>(),
-                    appPaths);
-            }
-            catch (Exception ex)
-            {
-                _logger.LogWarning(ex, $"Skia not available. Will fallback to {nameof(NullImageEncoder)}.");
-            }
-
-            return new NullImageEncoder();
-        }
-
         private static void StartNewInstance(StartupOptions options)
         {
             _logger.LogInformation("Starting new instance");

+ 8 - 1
MediaBrowser.Api/Images/ImageService.cs

@@ -332,7 +332,8 @@ namespace MediaBrowser.Api.Images
                     var fileInfo = _fileSystem.GetFileInfo(info.Path);
                     length = fileInfo.Length;
 
-                    ImageDimensions size = _imageProcessor.GetImageDimensions(item, info, true);
+                    ImageDimensions size = _imageProcessor.GetImageDimensions(item, info);
+                    _libraryManager.UpdateImages(item);
                     width = size.Width;
                     height = size.Height;
 
@@ -606,6 +607,12 @@ namespace MediaBrowser.Api.Images
             IDictionary<string, string> headers,
             bool isHeadRequest)
         {
+            if (!image.IsLocalFile)
+            {
+                item ??= _libraryManager.GetItemById(itemId);
+                image = await _libraryManager.ConvertImageToLocal(item, image, request.Index ?? 0).ConfigureAwait(false);
+            }
+
             var options = new ImageProcessingOptions
             {
                 CropWhiteSpace = cropwhitespace,

+ 1 - 5
MediaBrowser.Common/IApplicationHost.cs

@@ -2,8 +2,6 @@ using System;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Plugins;
-using MediaBrowser.Model.Updates;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 
 namespace MediaBrowser.Common
@@ -119,9 +117,7 @@ namespace MediaBrowser.Common
         /// Initializes this instance.
         /// </summary>
         /// <param name="serviceCollection">The service collection.</param>
-        /// <param name="startupConfig">The configuration to use for initialization.</param>
-        /// <returns>A task.</returns>
-        Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig);
+        void Init(IServiceCollection serviceCollection);
 
         /// <summary>
         /// Creates the instance.

+ 0 - 9
MediaBrowser.Controller/Drawing/IImageProcessor.cs

@@ -40,15 +40,6 @@ namespace MediaBrowser.Controller.Drawing
         /// <returns>ImageDimensions</returns>
         ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info);
 
-        /// <summary>
-        /// Gets the dimensions of the image.
-        /// </summary>
-        /// <param name="item">The base item.</param>
-        /// <param name="info">The information.</param>
-        /// <param name="updateItem">Whether or not the item info should be updated.</param>
-        /// <returns>ImageDimensions</returns>
-        ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem);
-
         /// <summary>
         /// Gets the image cache tag.
         /// </summary>

+ 1 - 1
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -459,7 +459,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
                 var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions);
                 var outputVideoCodec = GetVideoEncoder(state, encodingOptions);
-				
+
                 var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
 
                 if (!hasTextSubs)

+ 4 - 13
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -19,7 +19,6 @@ using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.System;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using System.Diagnostics;
 
@@ -39,8 +38,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
         private readonly IServerConfigurationManager _configurationManager;
         private readonly IFileSystem _fileSystem;
         private readonly ILocalizationManager _localization;
-        private readonly Func<ISubtitleEncoder> _subtitleEncoder;
-        private readonly IConfiguration _configuration;
+        private readonly Lazy<EncodingHelper> _encodingHelperFactory;
         private readonly string _startupOptionFFmpegPath;
 
         private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
@@ -48,8 +46,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
         private readonly object _runningProcessesLock = new object();
         private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
 
-        private EncodingHelper _encodingHelper;
-
         private string _ffmpegPath;
         private string _ffprobePath;
 
@@ -58,23 +54,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
             IServerConfigurationManager configurationManager,
             IFileSystem fileSystem,
             ILocalizationManager localization,
-            Func<ISubtitleEncoder> subtitleEncoder,
-            IConfiguration configuration,
+            Lazy<EncodingHelper> encodingHelperFactory,
             string startupOptionsFFmpegPath)
         {
             _logger = logger;
             _configurationManager = configurationManager;
             _fileSystem = fileSystem;
             _localization = localization;
+            _encodingHelperFactory = encodingHelperFactory;
             _startupOptionFFmpegPath = startupOptionsFFmpegPath;
-            _subtitleEncoder = subtitleEncoder;
-            _configuration = configuration;
         }
 
-        private EncodingHelper EncodingHelper
-            => LazyInitializer.EnsureInitialized(
-                ref _encodingHelper,
-                () => new EncodingHelper(this, _fileSystem, _subtitleEncoder(), _configuration));
+        private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
 
         /// <inheritdoc />
         public string EncoderPath => _ffmpegPath;

+ 32 - 41
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -36,60 +36,51 @@ namespace MediaBrowser.Providers.Manager
     /// </summary>
     public class ProviderManager : IProviderManager, IDisposable
     {
-        /// <summary>
-        /// The _logger
-        /// </summary>
         private readonly ILogger _logger;
-
-        /// <summary>
-        /// The _HTTP client
-        /// </summary>
         private readonly IHttpClient _httpClient;
-
-        /// <summary>
-        /// The _directory watchers
-        /// </summary>
         private readonly ILibraryMonitor _libraryMonitor;
-
-        /// <summary>
-        /// Gets or sets the configuration manager.
-        /// </summary>
-        /// <value>The configuration manager.</value>
-        private IServerConfigurationManager ConfigurationManager { get; set; }
+        private readonly IFileSystem _fileSystem;
+        private readonly IServerApplicationPaths _appPaths;
+        private readonly IJsonSerializer _json;
+        private readonly ILibraryManager _libraryManager;
+        private readonly ISubtitleManager _subtitleManager;
+        private readonly IServerConfigurationManager _configurationManager;
 
         private IImageProvider[] ImageProviders { get; set; }
 
-        private readonly IFileSystem _fileSystem;
-
         private IMetadataService[] _metadataServices = { };
         private IMetadataProvider[] _metadataProviders = { };
         private IEnumerable<IMetadataSaver> _savers;
-        private readonly IServerApplicationPaths _appPaths;
-        private readonly IJsonSerializer _json;
 
         private IExternalId[] _externalIds;
 
-        private readonly Func<ILibraryManager> _libraryManagerFactory;
         private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
 
         public event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
         public event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
         public event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress;
 
-        private ISubtitleManager _subtitleManager;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
         /// </summary>
-        public ProviderManager(IHttpClient httpClient, ISubtitleManager subtitleManager, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILoggerFactory loggerFactory, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory, IJsonSerializer json)
+        public ProviderManager(
+            IHttpClient httpClient,
+            ISubtitleManager subtitleManager,
+            IServerConfigurationManager configurationManager,
+            ILibraryMonitor libraryMonitor,
+            ILogger<ProviderManager> logger,
+            IFileSystem fileSystem,
+            IServerApplicationPaths appPaths,
+            ILibraryManager libraryManager,
+            IJsonSerializer json)
         {
-            _logger = loggerFactory.CreateLogger("ProviderManager");
+            _logger = logger;
             _httpClient = httpClient;
-            ConfigurationManager = configurationManager;
+            _configurationManager = configurationManager;
             _libraryMonitor = libraryMonitor;
             _fileSystem = fileSystem;
             _appPaths = appPaths;
-            _libraryManagerFactory = libraryManagerFactory;
+            _libraryManager = libraryManager;
             _json = json;
             _subtitleManager = subtitleManager;
         }
@@ -176,7 +167,7 @@ namespace MediaBrowser.Providers.Manager
 
         public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
         {
-            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
+            return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
         }
 
         public Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
@@ -188,7 +179,7 @@ namespace MediaBrowser.Providers.Manager
 
             var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, true);
 
-            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
+            return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
         }
 
         public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken)
@@ -273,7 +264,7 @@ namespace MediaBrowser.Providers.Manager
 
         public IEnumerable<IImageProvider> GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions)
         {
-            return GetImageProviders(item, _libraryManagerFactory().GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false);
+            return GetImageProviders(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false);
         }
 
         private IEnumerable<IImageProvider> GetImageProviders(BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled)
@@ -328,7 +319,7 @@ namespace MediaBrowser.Providers.Manager
         private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(BaseItem item, bool includeDisabled)
         {
             var options = GetMetadataOptions(item);
-            var libraryOptions = _libraryManagerFactory().GetLibraryOptions(item);
+            var libraryOptions = _libraryManager.GetLibraryOptions(item);
 
             return GetImageProviders(item, libraryOptions, options,
                     new ImageRefreshOptions(
@@ -593,7 +584,7 @@ namespace MediaBrowser.Providers.Manager
         {
             var type = item.GetType().Name;
 
-            return ConfigurationManager.Configuration.MetadataOptions
+            return _configurationManager.Configuration.MetadataOptions
                 .FirstOrDefault(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase)) ??
                 new MetadataOptions();
         }
@@ -623,7 +614,7 @@ namespace MediaBrowser.Providers.Manager
         /// <returns>Task.</returns>
         private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers)
         {
-            var libraryOptions = _libraryManagerFactory().GetLibraryOptions(item);
+            var libraryOptions = _libraryManager.GetLibraryOptions(item);
 
             foreach (var saver in savers.Where(i => IsSaverEnabledForItem(i, item, libraryOptions, updateType, false)))
             {
@@ -743,7 +734,7 @@ namespace MediaBrowser.Providers.Manager
 
             if (!searchInfo.ItemId.Equals(Guid.Empty))
             {
-                referenceItem = _libraryManagerFactory().GetItemById(searchInfo.ItemId);
+                referenceItem = _libraryManager.GetItemById(searchInfo.ItemId);
             }
 
             return GetRemoteSearchResults<TItemType, TLookupType>(searchInfo, referenceItem, cancellationToken);
@@ -771,7 +762,7 @@ namespace MediaBrowser.Providers.Manager
             }
             else
             {
-                libraryOptions = _libraryManagerFactory().GetLibraryOptions(referenceItem);
+                libraryOptions = _libraryManager.GetLibraryOptions(referenceItem);
             }
 
             var options = GetMetadataOptions(referenceItem);
@@ -786,11 +777,11 @@ namespace MediaBrowser.Providers.Manager
 
             if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage))
             {
-                searchInfo.SearchInfo.MetadataLanguage = ConfigurationManager.Configuration.PreferredMetadataLanguage;
+                searchInfo.SearchInfo.MetadataLanguage = _configurationManager.Configuration.PreferredMetadataLanguage;
             }
             if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode))
             {
-                searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode;
+                searchInfo.SearchInfo.MetadataCountryCode = _configurationManager.Configuration.MetadataCountryCode;
             }
 
             var resultList = new List<RemoteSearchResult>();
@@ -967,7 +958,7 @@ namespace MediaBrowser.Providers.Manager
         public void OnRefreshProgress(BaseItem item, double progress)
         {
             var id = item.Id;
-            _logger.LogInformation("OnRefreshProgress {0} {1}", id.ToString("N", CultureInfo.InvariantCulture), progress);
+            _logger.LogDebug("OnRefreshProgress {0} {1}", id.ToString("N", CultureInfo.InvariantCulture), progress);
 
             // TODO: Need to hunt down the conditions for this happening
             _activeRefreshes.AddOrUpdate(
@@ -1010,7 +1001,7 @@ namespace MediaBrowser.Providers.Manager
 
         private async Task StartProcessingRefreshQueue()
         {
-            var libraryManager = _libraryManagerFactory();
+            var libraryManager = _libraryManager;
 
             if (_disposed)
             {
@@ -1088,7 +1079,7 @@ namespace MediaBrowser.Providers.Manager
 
         private async Task RefreshArtist(MusicArtist item, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
-            var albums = _libraryManagerFactory()
+            var albums = _libraryManager
                 .GetItemList(new InternalItemsQuery
                 {
                     IncludeItemTypes = new[] { nameof(MusicAlbum) },

+ 4 - 4
MediaBrowser.Providers/Subtitles/SubtitleManager.cs

@@ -25,22 +25,22 @@ namespace MediaBrowser.Providers.Subtitles
 {
     public class SubtitleManager : ISubtitleManager
     {
-        private ISubtitleProvider[] _subtitleProviders;
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly ILibraryMonitor _monitor;
         private readonly IMediaSourceManager _mediaSourceManager;
+        private readonly ILocalizationManager _localization;
 
-        private ILocalizationManager _localization;
+        private ISubtitleProvider[] _subtitleProviders;
 
         public SubtitleManager(
-            ILoggerFactory loggerFactory,
+            ILogger<SubtitleManager> logger,
             IFileSystem fileSystem,
             ILibraryMonitor monitor,
             IMediaSourceManager mediaSourceManager,
             ILocalizationManager localizationManager)
         {
-            _logger = loggerFactory.CreateLogger(nameof(SubtitleManager));
+            _logger = logger;
             _fileSystem = fileSystem;
             _monitor = monitor;
             _mediaSourceManager = mediaSourceManager;