diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ae020826d..7d77500ab 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -104,10 +104,10 @@ using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Subtitles; using MediaBrowser.WebDashboard.Api; using MediaBrowser.XbmcMetadata.Providers; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; using ServiceStack; -using ServiceStack.Text.Jsv; using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate; namespace Emby.Server.Implementations @@ -318,6 +318,8 @@ namespace Emby.Server.Implementations private IMediaSourceManager MediaSourceManager { get; set; } private IPlaylistManager PlaylistManager { get; set; } + private readonly IConfiguration _configuration; + /// /// Gets or sets the installation manager. /// @@ -356,8 +358,10 @@ namespace Emby.Server.Implementations IFileSystem fileSystem, IEnvironmentInfo environmentInfo, IImageEncoder imageEncoder, - INetworkManager networkManager) + INetworkManager networkManager, + IConfiguration configuration) { + _configuration = configuration; // hack alert, until common can target .net core BaseExtensions.CryptographyProvider = CryptographyProvider; @@ -727,11 +731,10 @@ namespace Emby.Server.Implementations HttpServer = new HttpListenerHost(this, LoggerFactory, ServerConfigurationManager, - "web/index.html", + _configuration, NetworkManager, JsonSerializer, - XmlSerializer, - GetParseFn); + XmlSerializer); HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); serviceCollection.AddSingleton(HttpServer); @@ -831,11 +834,6 @@ namespace Emby.Server.Implementations return null; } - private static Func GetParseFn(Type propertyType) - { - return s => JsvReader.GetParseFn(propertyType)(s); - } - public virtual string PackageRuntime => "netcore"; public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, EnvironmentInfo.EnvironmentInfo environmentInfo) diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs new file mode 100644 index 000000000..30bfd8749 --- /dev/null +++ b/Emby.Server.Implementations/ConfigurationOptions.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Emby.Server.Implementations +{ + public static class ConfigurationOptions + { + public static readonly Dictionary Configuration = new Dictionary + { + {"HttpListenerHost:DefaultRedirectPath", "web/index.html"} + }; + } +} diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 6bf776f53..bbf165d62 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -24,6 +24,7 @@ + diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 834ffb130..d78891ac7 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -19,7 +19,9 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using ServiceStack.Text.Jsv; namespace Emby.Server.Implementations.HttpServer { @@ -53,20 +55,20 @@ namespace Emby.Server.Implementations.HttpServer IServerApplicationHost applicationHost, ILoggerFactory loggerFactory, IServerConfigurationManager config, - string defaultRedirectPath, + IConfiguration configuration, INetworkManager networkManager, IJsonSerializer jsonSerializer, - IXmlSerializer xmlSerializer, - Func> funcParseFn) + IXmlSerializer xmlSerializer) { _appHost = applicationHost; _logger = loggerFactory.CreateLogger("HttpServer"); _config = config; - DefaultRedirectPath = defaultRedirectPath; + DefaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"]; _networkManager = networkManager; _jsonSerializer = jsonSerializer; _xmlSerializer = xmlSerializer; - _funcParseFn = funcParseFn; + + _funcParseFn = t => s => JsvReader.GetParseFn(t)(s); Instance = this; ResponseFilters = Array.Empty>(); diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 7c44878ec..a64dfb607 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -4,8 +4,10 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using MediaBrowser.Common.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.IO @@ -20,61 +22,27 @@ namespace Emby.Server.Implementations.IO private readonly bool _supportsAsyncFileStreams; private char[] _invalidFileNameChars; private readonly List _shortcutHandlers = new List(); - private bool EnableSeparateFileAndDirectoryQueries; - private string _tempPath; + private readonly string _tempPath; - private IEnvironmentInfo _environmentInfo; - private bool _isEnvironmentCaseInsensitive; - - private string _defaultDirectory; + private readonly IEnvironmentInfo _environmentInfo; + private readonly bool _isEnvironmentCaseInsensitive; public ManagedFileSystem( ILoggerFactory loggerFactory, IEnvironmentInfo environmentInfo, - string defaultDirectory, - string tempPath, - bool enableSeparateFileAndDirectoryQueries) + IApplicationPaths applicationPaths) { Logger = loggerFactory.CreateLogger("FileSystem"); _supportsAsyncFileStreams = true; - _tempPath = tempPath; + _tempPath = applicationPaths.TempDirectory; _environmentInfo = environmentInfo; - _defaultDirectory = defaultDirectory; - - // On Linux with mono, this needs to be true or symbolic links are ignored - EnableSeparateFileAndDirectoryQueries = enableSeparateFileAndDirectoryQueries; SetInvalidFileNameChars(environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows); _isEnvironmentCaseInsensitive = environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows; } - public virtual string DefaultDirectory - { - get - { - var value = _defaultDirectory; - - if (!string.IsNullOrEmpty(value)) - { - try - { - if (Directory.Exists(value)) - { - return value; - } - } - catch - { - - } - } - - return null; - } - } - public virtual void AddShortcutHandler(IShortcutHandler handler) { _shortcutHandlers.Add(handler); @@ -718,7 +686,7 @@ namespace Emby.Server.Implementations.IO SetAttributes(path, false, false); File.Delete(path); } - + public virtual List GetDrives() { // Only include drives in the ready state or this method could end up being very slow, waiting for drives to timeout @@ -777,20 +745,15 @@ namespace Emby.Server.Implementations.IO var directoryInfo = new DirectoryInfo(path); var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; - if (EnableSeparateFileAndDirectoryQueries) - { - return ToMetadata(directoryInfo.EnumerateDirectories("*", searchOption)) - .Concat(ToMetadata(directoryInfo.EnumerateFiles("*", searchOption))); - } - - return ToMetadata(directoryInfo.EnumerateFileSystemInfos("*", searchOption)); + return ToMetadata(directoryInfo.EnumerateDirectories("*", searchOption)) + .Concat(ToMetadata(directoryInfo.EnumerateFiles("*", searchOption))); } private IEnumerable ToMetadata(IEnumerable infos) { return infos.Select(GetFileSystemMetadata); } - + public virtual IEnumerable GetDirectoryPaths(string path, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 126cb467f..84d78d3fb 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -5,14 +5,31 @@ using Emby.Server.Implementations.HttpServer; using Jellyfin.Server.SocketSharp; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Jellyfin.Server { public class CoreAppHost : ApplicationHost { - public CoreAppHost(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, StartupOptions options, IFileSystem fileSystem, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, MediaBrowser.Common.Net.INetworkManager networkManager) - : base(applicationPaths, loggerFactory, options, fileSystem, environmentInfo, imageEncoder, networkManager) + public CoreAppHost( + ServerApplicationPaths applicationPaths, + ILoggerFactory loggerFactory, + StartupOptions options, + IFileSystem fileSystem, + IEnvironmentInfo environmentInfo, + MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, + MediaBrowser.Common.Net.INetworkManager networkManager, + IConfiguration configuration) + : base( + applicationPaths, + loggerFactory, + options, + fileSystem, + environmentInfo, + imageEncoder, + networkManager, + configuration) { } diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index ac5aab460..2a2f1dde6 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -35,6 +35,7 @@ namespace Jellyfin.Server private static readonly ILoggerFactory _loggerFactory = new SerilogLoggerFactory(); private static ILogger _logger; private static bool _restartOnShutdown; + private static IConfiguration appConfig; public static async Task Main(string[] args) { @@ -78,7 +79,11 @@ namespace Jellyfin.Server // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath); - await CreateLogger(appPaths).ConfigureAwait(false); + + appConfig = await CreateConfiguration(appPaths).ConfigureAwait(false); + + CreateLogger(appConfig, appPaths); + _logger = _loggerFactory.CreateLogger("Main"); AppDomain.CurrentDomain.UnhandledException += (sender, e) @@ -121,7 +126,7 @@ namespace Jellyfin.Server // Allow all https requests ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; } ); - var fileSystem = new ManagedFileSystem(_loggerFactory, environmentInfo, null, appPaths.TempDirectory, true); + var fileSystem = new ManagedFileSystem(_loggerFactory, environmentInfo, appPaths); using (var appHost = new CoreAppHost( appPaths, @@ -130,7 +135,8 @@ namespace Jellyfin.Server fileSystem, environmentInfo, new NullImageEncoder(), - new NetworkManager(_loggerFactory, environmentInfo))) + new NetworkManager(_loggerFactory, environmentInfo), + appConfig)) { await appHost.Init(new ServiceCollection()).ConfigureAwait(false); @@ -309,29 +315,33 @@ namespace Jellyfin.Server return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir); } - private static async Task CreateLogger(IApplicationPaths appPaths) + private static async Task CreateConfiguration(IApplicationPaths appPaths) + { + string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, "logging.json"); + + if (!File.Exists(configPath)) + { + // For some reason the csproj name is used instead of the assembly name + using (Stream rscstr = typeof(Program).Assembly + .GetManifestResourceStream("Jellyfin.Server.Resources.Configuration.logging.json")) + using (Stream fstr = File.Open(configPath, FileMode.CreateNew)) + { + await rscstr.CopyToAsync(fstr).ConfigureAwait(false); + } + } + + return new ConfigurationBuilder() + .SetBasePath(appPaths.ConfigurationDirectoryPath) + .AddJsonFile("logging.json") + .AddEnvironmentVariables("JELLYFIN_") + .AddInMemoryCollection(ConfigurationOptions.Configuration) + .Build(); + } + + private static void CreateLogger(IConfiguration configuration, IApplicationPaths appPaths) { try { - string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, "logging.json"); - - if (!File.Exists(configPath)) - { - // For some reason the csproj name is used instead of the assembly name - using (Stream rscstr = typeof(Program).Assembly - .GetManifestResourceStream("Jellyfin.Server.Resources.Configuration.logging.json")) - using (Stream fstr = File.Open(configPath, FileMode.CreateNew)) - { - await rscstr.CopyToAsync(fstr).ConfigureAwait(false); - } - } - - var configuration = new ConfigurationBuilder() - .SetBasePath(appPaths.ConfigurationDirectoryPath) - .AddJsonFile("logging.json") - .AddEnvironmentVariables("JELLYFIN_") - .Build(); - // Serilog.Log is used by SerilogLoggerFactory when no logger is specified Serilog.Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index bdd7a8f8f..f4813e713 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -173,14 +173,8 @@ namespace MediaBrowser.Api _fileSystem.DeleteFile(file); } - public object Get(GetDefaultDirectoryBrowser request) - { - var result = new DefaultDirectoryBrowserInfo(); - - result.Path = _fileSystem.DefaultDirectory; - - return ToOptimizedResult(result); - } + public object Get(GetDefaultDirectoryBrowser request) => + ToOptimizedResult(new DefaultDirectoryBrowserInfo {Path = null}); /// /// Gets the specified request. diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index 6c9b2bd88..e0771245f 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -113,8 +113,6 @@ namespace MediaBrowser.Model.IO Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions); - string DefaultDirectory { get; } - /// /// Swaps the files. ///