From decaffed86cbc5db99c3f79d266fdfcdd262c12d Mon Sep 17 00:00:00 2001
From: Bond-009 <bond.009@outlook.com>
Date: Thu, 7 Mar 2019 17:39:40 +0100
Subject: [PATCH] Remove EnvironmentInfo

This moved the last bit of usefulness of EnvironmentInfo into a static
class.
---
 Emby.Dlna/Main/DlnaEntryPoint.cs              | 13 ++--
 .../IsoMounter/LinuxIsoManager.cs             | 10 ++-
 .../ApplicationHost.cs                        | 47 ++++--------
 .../EnvironmentInfo/EnvironmentInfo.cs        | 36 ----------
 .../IO/LibraryMonitor.cs                      | 15 +---
 .../IO/ManagedFileSystem.cs                   | 16 ++---
 .../Networking/NetworkManager.cs              |  8 +--
 Jellyfin.Server/CoreAppHost.cs                |  3 -
 Jellyfin.Server/Program.cs                    | 51 ++-----------
 MediaBrowser.Api/LiveTv/LiveTvService.cs      |  8 +--
 .../LiveTv/ProgressiveFileCopier.cs           |  8 +--
 .../Playback/Progressive/AudioService.cs      |  8 +--
 .../BaseProgressiveStreamingService.cs        | 15 ++--
 .../Progressive/ProgressiveStreamWriter.cs    | 10 ++-
 .../Playback/Progressive/VideoService.cs      |  8 +--
 .../Playback/UniversalAudioService.cs         |  7 +-
 MediaBrowser.Common/IApplicationHost.cs       |  3 +-
 MediaBrowser.Common/System/OperatingSystem.cs | 72 +++++++++++++++++++
 MediaBrowser.Model/System/IEnvironmentInfo.cs | 21 ------
 .../System/OperatingSystemId.cs               | 10 +++
 20 files changed, 144 insertions(+), 225 deletions(-)
 delete mode 100644 Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs
 create mode 100644 MediaBrowser.Common/System/OperatingSystem.cs
 delete mode 100644 MediaBrowser.Model/System/IEnvironmentInfo.cs
 create mode 100644 MediaBrowser.Model/System/OperatingSystemId.cs

diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 57ed0097a0..919a8f46f8 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using Emby.Dlna.PlayTo;
@@ -24,6 +23,7 @@ using MediaBrowser.Model.Xml;
 using Microsoft.Extensions.Logging;
 using Rssdp;
 using Rssdp.Infrastructure;
+using OperatingSystem =  MediaBrowser.Common.System.OperatingSystem;
 
 namespace Emby.Dlna.Main
 {
@@ -48,9 +48,8 @@ namespace Emby.Dlna.Main
         private readonly IDeviceDiscovery _deviceDiscovery;
 
         private SsdpDevicePublisher _Publisher;
-        
+
         private readonly ISocketFactory _socketFactory;
-        private readonly IEnvironmentInfo _environmentInfo;
         private readonly INetworkManager _networkManager;
 
         private ISsdpCommunicationsServer _communicationsServer;
@@ -76,7 +75,6 @@ namespace Emby.Dlna.Main
             IDeviceDiscovery deviceDiscovery,
             IMediaEncoder mediaEncoder,
             ISocketFactory socketFactory,
-            IEnvironmentInfo environmentInfo,
             INetworkManager networkManager,
             IUserViewManager userViewManager,
             IXmlReaderSettingsFactory xmlReaderSettingsFactory,
@@ -96,7 +94,6 @@ namespace Emby.Dlna.Main
             _deviceDiscovery = deviceDiscovery;
             _mediaEncoder = mediaEncoder;
             _socketFactory = socketFactory;
-            _environmentInfo = environmentInfo;
             _networkManager = networkManager;
             _logger = loggerFactory.CreateLogger("Dlna");
 
@@ -169,8 +166,8 @@ namespace Emby.Dlna.Main
             {
                 if (_communicationsServer == null)
                 {
-                    var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows ||
-                                                   _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux;
+                    var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows ||
+                                                   OperatingSystem.Id == OperatingSystemId.Linux;
 
                     _communicationsServer = new SsdpCommunicationsServer(_config, _socketFactory, _networkManager, _logger, enableMultiSocketBinding)
                     {
@@ -230,7 +227,7 @@ namespace Emby.Dlna.Main
 
             try
             {
-                _Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion, _config.GetDlnaConfiguration().SendOnlyMatchedHost);
+                _Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost);
                 _Publisher.LogFunction = LogMessage;
                 _Publisher.SupportPnpRootDevice = false;
 
diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
index 943caa3e62..2f0003be88 100644
--- a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
+++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Diagnostics;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace IsoMounter
 {
@@ -17,7 +18,6 @@ namespace IsoMounter
 
         #region Private Fields
 
-        private readonly IEnvironmentInfo EnvironmentInfo;
         private readonly bool ExecutablesAvailable;
         private readonly ILogger _logger;
         private readonly string MountCommand;
@@ -30,10 +30,8 @@ namespace IsoMounter
 
         #region Constructor(s)
 
-        public LinuxIsoManager(ILogger logger, IEnvironmentInfo environment, IProcessFactory processFactory)
+        public LinuxIsoManager(ILogger logger, IProcessFactory processFactory)
         {
-
-            EnvironmentInfo = environment;
             _logger = logger;
             ProcessFactory = processFactory;
 
@@ -109,7 +107,7 @@ namespace IsoMounter
         public bool CanMount(string path)
         {
 
-            if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Linux)
+            if (OperatingSystem.Id != OperatingSystemId.Linux)
             {
                 return false;
             }
@@ -118,7 +116,7 @@ namespace IsoMounter
                 Name,
                 path,
                 Path.GetExtension(path),
-                EnvironmentInfo.OperatingSystem,
+                OperatingSystem.Name,
                 ExecutablesAvailable
             );
 
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index a581214c71..964d173421 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -115,6 +115,7 @@ using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using ServiceStack;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace Emby.Server.Implementations
 {
@@ -143,12 +144,8 @@ namespace Emby.Server.Implementations
                     return false;
                 }
 
-                if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
-                {
-                    return true;
-                }
-
-                if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
+                if (OperatingSystem.Id == OperatingSystemId.Windows
+                    || OperatingSystem.Id == OperatingSystemId.Darwin)
                 {
                     return true;
                 }
@@ -218,8 +215,6 @@ namespace Emby.Server.Implementations
 
         public IFileSystem FileSystemManager { get; set; }
 
-        protected IEnvironmentInfo EnvironmentInfo { get; set; }
-
         public PackageVersionClass SystemUpdateLevel
         {
             get
@@ -239,15 +234,6 @@ namespace Emby.Server.Implementations
         /// <value>The server configuration manager.</value>
         public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
 
-        /// <summary>
-        /// Gets the configuration manager.
-        /// </summary>
-        /// <returns>IConfigurationManager.</returns>
-        protected IConfigurationManager GetConfigurationManager()
-        {
-            return new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager);
-        }
-
         protected virtual IResourceFileManager CreateResourceFileManager()
         {
             return new ResourceFileManager(HttpResultFactory, LoggerFactory, FileSystemManager);
@@ -356,7 +342,6 @@ namespace Emby.Server.Implementations
             ILoggerFactory loggerFactory,
             IStartupOptions options,
             IFileSystem fileSystem,
-            IEnvironmentInfo environmentInfo,
             IImageEncoder imageEncoder,
             INetworkManager networkManager,
             IConfiguration configuration)
@@ -370,13 +355,12 @@ namespace Emby.Server.Implementations
 
             NetworkManager = networkManager;
             networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
-            EnvironmentInfo = environmentInfo;
 
             ApplicationPaths = applicationPaths;
             LoggerFactory = loggerFactory;
             FileSystemManager = fileSystem;
 
-            ConfigurationManager = GetConfigurationManager();
+            ConfigurationManager = new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager);
 
             Logger = LoggerFactory.CreateLogger("App");
 
@@ -532,7 +516,7 @@ namespace Emby.Server.Implementations
         /// <summary>
         /// Runs the startup tasks.
         /// </summary>
-        public async Task RunStartupTasks()
+        public async Task RunStartupTasksAsync()
         {
             Logger.LogInformation("Running startup tasks");
 
@@ -584,7 +568,7 @@ namespace Emby.Server.Implementations
             }
         }
 
-        public async Task Init(IServiceCollection serviceCollection)
+        public async Task InitAsync(IServiceCollection serviceCollection)
         {
             HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
             HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -706,8 +690,6 @@ namespace Emby.Server.Implementations
             serviceCollection.AddLogging();
             serviceCollection.AddSingleton(Logger);
 
-            serviceCollection.AddSingleton(EnvironmentInfo);
-
             serviceCollection.AddSingleton(FileSystemManager);
             serviceCollection.AddSingleton<TvDbClientManager>();
 
@@ -786,7 +768,7 @@ namespace Emby.Server.Implementations
             var musicManager = new MusicManager(LibraryManager);
             serviceCollection.AddSingleton<IMusicManager>(new MusicManager(LibraryManager));
 
-            LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager, EnvironmentInfo);
+            LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
             serviceCollection.AddSingleton(LibraryMonitor);
 
             serviceCollection.AddSingleton<ISearchEngine>(new SearchEngine(LoggerFactory, LibraryManager, UserManager));
@@ -907,7 +889,7 @@ namespace Emby.Server.Implementations
 
         public virtual string PackageRuntime => "netcore";
 
-        public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, EnvironmentInfo.EnvironmentInfo environmentInfo)
+        public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths)
         {
             // Distinct these to prevent users from reporting problems that aren't actually problems
             var commandLineArgs = Environment
@@ -915,8 +897,9 @@ namespace Emby.Server.Implementations
                 .Distinct();
 
             logger.LogInformation("Arguments: {Args}", commandLineArgs);
-            logger.LogInformation("Operating system: {OS} {OSVersion}", environmentInfo.OperatingSystemName, environmentInfo.OperatingSystemVersion);
-            logger.LogInformation("Architecture: {Architecture}", environmentInfo.SystemArchitecture);
+            // FIXME: @bond this logs the kernel version, not the OS version
+            logger.LogInformation("Operating system: {OS} {OSVersion}", OperatingSystem.Name, Environment.OSVersion.Version);
+            logger.LogInformation("Architecture: {Architecture}", RuntimeInformation.OSArchitecture);
             logger.LogInformation("64-Bit Process: {Is64Bit}", Environment.Is64BitProcess);
             logger.LogInformation("User Interactive: {IsUserInteractive}", Environment.UserInteractive);
             logger.LogInformation("Processor count: {ProcessorCount}", Environment.ProcessorCount);
@@ -1400,8 +1383,8 @@ namespace Emby.Server.Implementations
                 HttpServerPortNumber = HttpPort,
                 SupportsHttps = SupportsHttps,
                 HttpsPortNumber = HttpsPort,
-                OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
-                OperatingSystemDisplayName = EnvironmentInfo.OperatingSystemName,
+                OperatingSystem = OperatingSystem.Id.ToString(),
+                OperatingSystemDisplayName = OperatingSystem.Name,
                 CanSelfRestart = CanSelfRestart,
                 CanLaunchWebBrowser = CanLaunchWebBrowser,
                 WanAddress = wanAddress,
@@ -1411,7 +1394,7 @@ namespace Emby.Server.Implementations
                 LocalAddress = localAddress,
                 SupportsLibraryMonitor = true,
                 EncoderLocation = MediaEncoder.EncoderLocation,
-                SystemArchitecture = EnvironmentInfo.SystemArchitecture,
+                SystemArchitecture = RuntimeInformation.OSArchitecture,
                 SystemUpdateLevel = SystemUpdateLevel,
                 PackageName = StartupOptions.PackageName
             };
@@ -1435,7 +1418,7 @@ namespace Emby.Server.Implementations
             {
                 Version = ApplicationVersion,
                 Id = SystemId,
-                OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
+                OperatingSystem = OperatingSystem.Id.ToString(),
                 WanAddress = wanAddress,
                 ServerName = FriendlyName,
                 LocalAddress = localAddress
diff --git a/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs
deleted file mode 100644
index c8104150d6..0000000000
--- a/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using MediaBrowser.Model.System;
-
-namespace Emby.Server.Implementations.EnvironmentInfo
-{
-    public class EnvironmentInfo : IEnvironmentInfo
-    {
-        public EnvironmentInfo(MediaBrowser.Model.System.OperatingSystem operatingSystem)
-        {
-            OperatingSystem = operatingSystem;
-        }
-
-        public MediaBrowser.Model.System.OperatingSystem OperatingSystem { get; private set; }
-
-        public string OperatingSystemName
-        {
-            get
-            {
-                switch (OperatingSystem)
-                {
-                    case MediaBrowser.Model.System.OperatingSystem.Android: return "Android";
-                    case MediaBrowser.Model.System.OperatingSystem.BSD: return "BSD";
-                    case MediaBrowser.Model.System.OperatingSystem.Linux: return "Linux";
-                    case MediaBrowser.Model.System.OperatingSystem.OSX: return "macOS";
-                    case MediaBrowser.Model.System.OperatingSystem.Windows: return "Windows";
-                    default: throw new Exception($"Unknown OS {OperatingSystem}");
-                }
-            }
-        }
-
-        public string OperatingSystemVersion => Environment.OSVersion.Version.ToString() + " " + Environment.OSVersion.ServicePack.ToString();
-
-        public Architecture SystemArchitecture => RuntimeInformation.OSArchitecture;
-    }
-}
diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index d473425115..df4dc41b99 100644
--- a/Emby.Server.Implementations/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -10,8 +10,8 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.System;
-using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace Emby.Server.Implementations.IO
 {
@@ -127,7 +127,6 @@ namespace Emby.Server.Implementations.IO
         private IServerConfigurationManager ConfigurationManager { get; set; }
 
         private readonly IFileSystem _fileSystem;
-        private readonly IEnvironmentInfo _environmentInfo;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
@@ -136,14 +135,12 @@ namespace Emby.Server.Implementations.IO
             ILoggerFactory loggerFactory,
             ILibraryManager libraryManager,
             IServerConfigurationManager configurationManager,
-            IFileSystem fileSystem,
-            IEnvironmentInfo environmentInfo)
+            IFileSystem fileSystem)
         {
             LibraryManager = libraryManager;
             Logger = loggerFactory.CreateLogger(GetType().Name);
             ConfigurationManager = configurationManager;
             _fileSystem = fileSystem;
-            _environmentInfo = environmentInfo;
         }
 
         private bool IsLibraryMonitorEnabled(BaseItem item)
@@ -267,7 +264,7 @@ namespace Emby.Server.Implementations.IO
                 return;
             }
 
-            if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
+            if (OperatingSystem.Id != OperatingSystemId.Windows)
             {
                 if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase) || path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase))
                 {
@@ -276,12 +273,6 @@ namespace Emby.Server.Implementations.IO
                 }
             }
 
-            if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Android)
-            {
-                // causing crashing
-                return;
-            }
-
             // Already being watched
             if (_fileSystemWatchers.ContainsKey(path))
             {
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 421592fada..47cea7269d 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace Emby.Server.Implementations.IO
 {
@@ -24,22 +25,19 @@ namespace Emby.Server.Implementations.IO
 
         private readonly string _tempPath;
 
-        private readonly IEnvironmentInfo _environmentInfo;
         private readonly bool _isEnvironmentCaseInsensitive;
 
         public ManagedFileSystem(
             ILoggerFactory loggerFactory,
-            IEnvironmentInfo environmentInfo,
             IApplicationPaths applicationPaths)
         {
             Logger = loggerFactory.CreateLogger("FileSystem");
             _supportsAsyncFileStreams = true;
             _tempPath = applicationPaths.TempDirectory;
-            _environmentInfo = environmentInfo;
 
-            SetInvalidFileNameChars(environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows);
+            SetInvalidFileNameChars(OperatingSystem.Id == OperatingSystemId.Windows);
 
-            _isEnvironmentCaseInsensitive = environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
+            _isEnvironmentCaseInsensitive = OperatingSystem.Id == OperatingSystemId.Windows;
         }
 
         public virtual void AddShortcutHandler(IShortcutHandler handler)
@@ -468,7 +466,7 @@ namespace Emby.Server.Implementations.IO
 
         public virtual void SetHidden(string path, bool isHidden)
         {
-            if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
+            if (OperatingSystem.Id != MediaBrowser.Model.System.OperatingSystemId.Windows)
             {
                 return;
             }
@@ -492,7 +490,7 @@ namespace Emby.Server.Implementations.IO
 
         public virtual void SetReadOnly(string path, bool isReadOnly)
         {
-            if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
+            if (OperatingSystem.Id != MediaBrowser.Model.System.OperatingSystemId.Windows)
             {
                 return;
             }
@@ -516,7 +514,7 @@ namespace Emby.Server.Implementations.IO
 
         public virtual void SetAttributes(string path, bool isHidden, bool isReadOnly)
         {
-            if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
+            if (OperatingSystem.Id != MediaBrowser.Model.System.OperatingSystemId.Windows)
             {
                 return;
             }
@@ -801,7 +799,7 @@ namespace Emby.Server.Implementations.IO
 
         public virtual void SetExecutable(string path)
         {
-            if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
+            if (OperatingSystem.Id == MediaBrowser.Model.System.OperatingSystemId.Darwin)
             {
                 RunProcess("chmod", "+x \"" + path + "\"", Path.GetDirectoryName(path));
             }
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index ace93ebdee..c102f9eb55 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -7,11 +7,11 @@ using System.Net.NetworkInformation;
 using System.Net.Sockets;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace Emby.Server.Implementations.Networking
 {
@@ -22,14 +22,12 @@ namespace Emby.Server.Implementations.Networking
         public event EventHandler NetworkChanged;
         public Func<string[]> LocalSubnetsFn { get; set; }
 
-        public NetworkManager(
-            ILoggerFactory loggerFactory,
-            IEnvironmentInfo environment)
+        public NetworkManager(ILoggerFactory loggerFactory)
         {
             Logger = loggerFactory.CreateLogger(nameof(NetworkManager));
 
             // In FreeBSD these events cause a crash
-            if (environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.BSD)
+            if (OperatingSystem.Id != OperatingSystemId.BSD)
             {
                 try
                 {
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index 17259c7370..8e6ed7a7e5 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -3,7 +3,6 @@ using System.Reflection;
 using Emby.Server.Implementations;
 using Emby.Server.Implementations.HttpServer;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Model.System;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 
@@ -16,7 +15,6 @@ namespace Jellyfin.Server
             ILoggerFactory loggerFactory,
             StartupOptions options,
             IFileSystem fileSystem,
-            IEnvironmentInfo environmentInfo,
             MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder,
             MediaBrowser.Common.Net.INetworkManager networkManager,
             IConfiguration configuration)
@@ -25,7 +23,6 @@ namespace Jellyfin.Server
                 loggerFactory,
                 options,
                 fileSystem,
-                environmentInfo,
                 imageEncoder,
                 networkManager,
                 configuration)
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 0ef1711d4c..a60f2a4f61 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -12,7 +12,6 @@ using System.Threading.Tasks;
 using CommandLine;
 using Emby.Drawing;
 using Emby.Server.Implementations;
-using Emby.Server.Implementations.EnvironmentInfo;
 using Emby.Server.Implementations.IO;
 using Emby.Server.Implementations.Networking;
 using Jellyfin.Drawing.Skia;
@@ -46,7 +45,6 @@ namespace Jellyfin.Server
             const string pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx
             const string substitution = @"-$1"; // Prepend with additional single-hyphen
             var regex = new Regex(pattern);
-
             for (var i = 0; i < args.Length; i++)
             {
                 args[i] = regex.Replace(args[i], substitution);
@@ -54,9 +52,7 @@ namespace Jellyfin.Server
 
             // Parse the command line arguments and either start the app or exit indicating error
             await Parser.Default.ParseArguments<StartupOptions>(args)
-                .MapResult(
-                    options => StartApp(options),
-                    errs => Task.FromResult(0)).ConfigureAwait(false);
+                .MapResult(StartApp, _ => Task.CompletedTask).ConfigureAwait(false);
         }
 
         public static void Shutdown()
@@ -119,31 +115,29 @@ namespace Jellyfin.Server
 
             _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version);
 
-            EnvironmentInfo environmentInfo = new EnvironmentInfo(GetOperatingSystem());
-            ApplicationHost.LogEnvironmentInfo(_logger, appPaths, environmentInfo);
+            ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
 
             SQLitePCL.Batteries_V2.Init();
 
             // Allow all https requests
             ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
 
-            var fileSystem = new ManagedFileSystem(_loggerFactory, environmentInfo, appPaths);
+            var fileSystem = new ManagedFileSystem(_loggerFactory, appPaths);
 
             using (var appHost = new CoreAppHost(
                 appPaths,
                 _loggerFactory,
                 options,
                 fileSystem,
-                environmentInfo,
                 new NullImageEncoder(),
-                new NetworkManager(_loggerFactory, environmentInfo),
+                new NetworkManager(_loggerFactory),
                 appConfig))
             {
-                await appHost.Init(new ServiceCollection()).ConfigureAwait(false);
+                await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false);
 
                 appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager);
 
-                await appHost.RunStartupTasks().ConfigureAwait(false);
+                await appHost.RunStartupTasksAsync().ConfigureAwait(false);
 
                 try
                 {
@@ -179,7 +173,6 @@ namespace Jellyfin.Server
             // ELSE IF $XDG_DATA_HOME then use $XDG_DATA_HOME/jellyfin
             // ELSE    use $HOME/.local/share/jellyfin
             var dataDir = options.DataDir;
-
             if (string.IsNullOrEmpty(dataDir))
             {
                 dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH");
@@ -236,7 +229,6 @@ namespace Jellyfin.Server
             // ELSE IF XDG_CACHE_HOME, use $XDG_CACHE_HOME/jellyfin
             // ELSE    HOME/.cache/jellyfin
             var cacheDir = options.CacheDir;
-
             if (string.IsNullOrEmpty(cacheDir))
             {
                 cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR");
@@ -270,7 +262,6 @@ namespace Jellyfin.Server
             // ELSE IF --datadir, use <datadir>/log (assume portable run)
             // ELSE    <datadir>/log
             var logDir = options.LogDir;
-
             if (string.IsNullOrEmpty(logDir))
             {
                 logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR");
@@ -364,36 +355,6 @@ namespace Jellyfin.Server
             return new NullImageEncoder();
         }
 
-        private static MediaBrowser.Model.System.OperatingSystem GetOperatingSystem()
-        {
-            switch (Environment.OSVersion.Platform)
-            {
-                case PlatformID.MacOSX:
-                    return MediaBrowser.Model.System.OperatingSystem.OSX;
-                case PlatformID.Win32NT:
-                    return MediaBrowser.Model.System.OperatingSystem.Windows;
-                case PlatformID.Unix:
-                default:
-                    {
-                        string osDescription = RuntimeInformation.OSDescription;
-                        if (osDescription.Contains("linux", StringComparison.OrdinalIgnoreCase))
-                        {
-                            return MediaBrowser.Model.System.OperatingSystem.Linux;
-                        }
-                        else if (osDescription.Contains("darwin", StringComparison.OrdinalIgnoreCase))
-                        {
-                            return MediaBrowser.Model.System.OperatingSystem.OSX;
-                        }
-                        else if (osDescription.Contains("bsd", StringComparison.OrdinalIgnoreCase))
-                        {
-                            return MediaBrowser.Model.System.OperatingSystem.BSD;
-                        }
-
-                        throw new Exception($"Can't resolve OS with description: '{osDescription}'");
-                    }
-            }
-        }
-
         private static void StartNewInstance(StartupOptions options)
         {
             _logger.LogInformation("Starting new instance");
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 88ed734569..486d5e8a71 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -698,12 +698,11 @@ namespace MediaBrowser.Api.LiveTv
         private readonly IFileSystem _fileSystem;
         private readonly IAuthorizationContext _authContext;
         private readonly ISessionContext _sessionContext;
-        private readonly IEnvironmentInfo _environment;
         private ICryptoProvider _cryptographyProvider;
         private IStreamHelper _streamHelper;
         private IMediaSourceManager _mediaSourceManager;
 
-        public LiveTvService(ICryptoProvider crypto, IMediaSourceManager mediaSourceManager, IStreamHelper streamHelper, ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext, IEnvironmentInfo environment)
+        public LiveTvService(ICryptoProvider crypto, IMediaSourceManager mediaSourceManager, IStreamHelper streamHelper, ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext)
         {
             _liveTvManager = liveTvManager;
             _userManager = userManager;
@@ -714,7 +713,6 @@ namespace MediaBrowser.Api.LiveTv
             _fileSystem = fileSystem;
             _authContext = authContext;
             _sessionContext = sessionContext;
-            _environment = environment;
             _cryptographyProvider = crypto;
             _streamHelper = streamHelper;
             _mediaSourceManager = mediaSourceManager;
@@ -756,7 +754,7 @@ namespace MediaBrowser.Api.LiveTv
                 [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType(path)
             };
 
-            return new ProgressiveFileCopier(_fileSystem, _streamHelper, path, outputHeaders, Logger, _environment)
+            return new ProgressiveFileCopier(_fileSystem, _streamHelper, path, outputHeaders, Logger)
             {
                 AllowEndOfFile = false
             };
@@ -779,7 +777,7 @@ namespace MediaBrowser.Api.LiveTv
                 [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType("file." + request.Container)
             };
 
-            return new ProgressiveFileCopier(directStreamProvider, _streamHelper, outputHeaders, Logger, _environment)
+            return new ProgressiveFileCopier(directStreamProvider, _streamHelper, outputHeaders, Logger)
             {
                 AllowEndOfFile = false
             };
diff --git a/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs
index 8412bf66b9..51552d928b 100644
--- a/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs
+++ b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.LiveTv
@@ -23,25 +22,22 @@ namespace MediaBrowser.Api.LiveTv
         public bool AllowEndOfFile = true;
 
         private readonly IDirectStreamProvider _directStreamProvider;
-        private readonly IEnvironmentInfo _environment;
         private IStreamHelper _streamHelper;
 
-        public ProgressiveFileCopier(IFileSystem fileSystem, IStreamHelper streamHelper, string path, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment)
+        public ProgressiveFileCopier(IFileSystem fileSystem, IStreamHelper streamHelper, string path, Dictionary<string, string> outputHeaders, ILogger logger)
         {
             _fileSystem = fileSystem;
             _path = path;
             _outputHeaders = outputHeaders;
             _logger = logger;
-            _environment = environment;
             _streamHelper = streamHelper;
         }
 
-        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment)
+        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary<string, string> outputHeaders, ILogger logger)
         {
             _directStreamProvider = directStreamProvider;
             _outputHeaders = outputHeaders;
             _logger = logger;
-            _environment = environment;
             _streamHelper = streamHelper;
         }
 
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 48b4e2f24e..dfe4b2b8e9 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
@@ -11,7 +10,6 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
 
 namespace MediaBrowser.Api.Playback.Progressive
 {
@@ -46,8 +44,7 @@ namespace MediaBrowser.Api.Playback.Progressive
             IDeviceManager deviceManager,
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
-            IAuthorizationContext authorizationContext,
-            IEnvironmentInfo environmentInfo)
+            IAuthorizationContext authorizationContext)
                 : base(httpClient,
                     serverConfig,
                     userManager,
@@ -60,8 +57,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                     deviceManager,
                     mediaSourceManager,
                     jsonSerializer,
-                    authorizationContext,
-                    environmentInfo)
+                    authorizationContext)
         {
         }
 
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index f43f26b2f3..a2c20e38fd 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Globalization;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
@@ -8,15 +7,12 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
 using Microsoft.Net.Http.Headers;
 
 namespace MediaBrowser.Api.Playback.Progressive
@@ -26,7 +22,6 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public abstract class BaseProgressiveStreamingService : BaseStreamingService
     {
-        protected readonly IEnvironmentInfo EnvironmentInfo;
         protected IHttpClient HttpClient { get; private set; }
 
         public BaseProgressiveStreamingService(
@@ -42,8 +37,7 @@ namespace MediaBrowser.Api.Playback.Progressive
             IDeviceManager deviceManager,
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
-            IAuthorizationContext authorizationContext,
-            IEnvironmentInfo environmentInfo)
+            IAuthorizationContext authorizationContext)
             : base(serverConfig,
                 userManager,
                 libraryManager,
@@ -57,7 +51,6 @@ namespace MediaBrowser.Api.Playback.Progressive
                 jsonSerializer,
                 authorizationContext)
         {
-            EnvironmentInfo = environmentInfo;
             HttpClient = httpClient;
         }
 
@@ -157,7 +150,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                     // TODO: Don't hardcode this
                     outputHeaders[HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType("file.ts");
 
-                    return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None)
+                    return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, CancellationToken.None)
                     {
                         AllowEndOfFile = false
                     };
@@ -203,7 +196,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                         };
 
 
-                        return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None)
+                        return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, CancellationToken.None)
                         {
                             AllowEndOfFile = false
                         };
@@ -397,7 +390,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                     outputHeaders[item.Key] = item.Value;
                 }
 
-                return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, EnvironmentInfo, CancellationToken.None);
+                return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, CancellationToken.None);
             }
             finally
             {
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
index 3dd9de2a1b..6609120655 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace MediaBrowser.Api.Playback.Progressive
 {
@@ -27,9 +28,8 @@ namespace MediaBrowser.Api.Playback.Progressive
         public bool AllowEndOfFile = true;
 
         private readonly IDirectStreamProvider _directStreamProvider;
-        private readonly IEnvironmentInfo _environment;
 
-        public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+        public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken)
         {
             _fileSystem = fileSystem;
             _path = path;
@@ -37,17 +37,15 @@ namespace MediaBrowser.Api.Playback.Progressive
             _job = job;
             _logger = logger;
             _cancellationToken = cancellationToken;
-            _environment = environment;
         }
 
-        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken)
         {
             _directStreamProvider = directStreamProvider;
             _outputHeaders = outputHeaders;
             _job = job;
             _logger = logger;
             _cancellationToken = cancellationToken;
-            _environment = environment;
         }
 
         public IDictionary<string, string> Headers => _outputHeaders;
@@ -79,7 +77,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 var eofCount = 0;
 
                 // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
-                var allowAsyncFileRead = _environment.OperatingSystem != Model.System.OperatingSystem.Windows;
+                var allowAsyncFileRead = OperatingSystem.Id != OperatingSystemId.Windows;
 
                 using (var inputStream = GetInputStream(allowAsyncFileRead))
                 {
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index bf15cc756c..ab19fdc261 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
@@ -11,7 +10,6 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
 
 namespace MediaBrowser.Api.Playback.Progressive
 {
@@ -83,8 +81,7 @@ namespace MediaBrowser.Api.Playback.Progressive
             IDeviceManager deviceManager,
             IMediaSourceManager mediaSourceManager,
             IJsonSerializer jsonSerializer,
-            IAuthorizationContext authorizationContext,
-            IEnvironmentInfo environmentInfo)
+            IAuthorizationContext authorizationContext)
             : base(httpClient,
                 serverConfig,
                 userManager,
@@ -97,8 +94,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 deviceManager,
                 mediaSourceManager,
                 jsonSerializer,
-                authorizationContext,
-                environmentInfo)
+                authorizationContext)
         {
         }
 
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
index f97e88e986..b3d8bfe59f 100644
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs
@@ -18,7 +18,6 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
 
 namespace MediaBrowser.Api.Playback
@@ -93,7 +92,6 @@ namespace MediaBrowser.Api.Playback
             IAuthorizationContext authorizationContext,
             IImageProcessor imageProcessor,
             INetworkManager networkManager,
-            IEnvironmentInfo environmentInfo,
             ILoggerFactory loggerFactory)
         {
             HttpClient = httpClient;
@@ -112,7 +110,6 @@ namespace MediaBrowser.Api.Playback
             AuthorizationContext = authorizationContext;
             ImageProcessor = imageProcessor;
             NetworkManager = networkManager;
-            EnvironmentInfo = environmentInfo;
             _loggerFactory = loggerFactory;
             _logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
         }
@@ -133,7 +130,6 @@ namespace MediaBrowser.Api.Playback
         protected IAuthorizationContext AuthorizationContext { get; private set; }
         protected IImageProcessor ImageProcessor { get; private set; }
         protected INetworkManager NetworkManager { get; private set; }
-        protected IEnvironmentInfo EnvironmentInfo { get; private set; }
         private ILoggerFactory _loggerFactory;
         private ILogger _logger;
 
@@ -338,8 +334,7 @@ namespace MediaBrowser.Api.Playback
                     DeviceManager,
                     MediaSourceManager,
                     JsonSerializer,
-                    AuthorizationContext,
-                    EnvironmentInfo)
+                    AuthorizationContext)
                 {
                     Request = Request
                 };
diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs
index 3a4098612d..966448d630 100644
--- a/MediaBrowser.Common/IApplicationHost.cs
+++ b/MediaBrowser.Common/IApplicationHost.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Model.Events;
@@ -107,7 +106,7 @@ namespace MediaBrowser.Common
         /// <summary>
         /// Inits this instance.
         /// </summary>
-        Task Init(IServiceCollection serviceCollection);
+        Task InitAsync(IServiceCollection serviceCollection);
 
         /// <summary>
         /// Creates the instance.
diff --git a/MediaBrowser.Common/System/OperatingSystem.cs b/MediaBrowser.Common/System/OperatingSystem.cs
new file mode 100644
index 0000000000..640821d4d7
--- /dev/null
+++ b/MediaBrowser.Common/System/OperatingSystem.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using MediaBrowser.Model.System;
+
+namespace MediaBrowser.Common.System
+{
+    public static class OperatingSystem
+    {
+        // We can't use Interlocked.CompareExchange for enums
+        private static int _id = int.MaxValue;
+
+        public static OperatingSystemId Id
+        {
+            get
+            {
+                if (_id == int.MaxValue)
+                {
+                    Interlocked.CompareExchange(ref _id, (int)GetId(), int.MaxValue);
+                }
+
+                return (OperatingSystemId)_id;
+            }
+        }
+
+        public static string Name
+        {
+            get
+            {
+                switch (Id)
+                {
+                    case OperatingSystemId.BSD: return "BSD";
+                    case OperatingSystemId.Linux: return "Linux";
+                    case OperatingSystemId.Darwin: return "macOS";
+                    case OperatingSystemId.Windows: return "Windows";
+                    default: throw new Exception($"Unknown OS {Id}");
+                }
+            }
+        }
+
+        private static OperatingSystemId GetId()
+        {
+            switch (Environment.OSVersion.Platform)
+            {
+                // On .NET Core `MacOSX` got replaced by `Unix`, this case should never be hit.
+                case PlatformID.MacOSX:
+                    return OperatingSystemId.Darwin;
+                case PlatformID.Win32NT:
+                    return OperatingSystemId.Windows;
+                case PlatformID.Unix:
+                default:
+                    {
+                        string osDescription = RuntimeInformation.OSDescription;
+                        if (osDescription.IndexOf("linux", StringComparison.OrdinalIgnoreCase) != -1)
+                        {
+                            return OperatingSystemId.Linux;
+                        }
+                        else if (osDescription.IndexOf("darwin", StringComparison.OrdinalIgnoreCase) != -1)
+                        {
+                            return OperatingSystemId.Darwin;
+                        }
+                        else if (osDescription.IndexOf("bsd", StringComparison.OrdinalIgnoreCase) != -1)
+                        {
+                            return OperatingSystemId.BSD;
+                        }
+
+                        throw new Exception($"Can't resolve OS with description: '{osDescription}'");
+                    }
+            }
+        }
+    }
+}
diff --git a/MediaBrowser.Model/System/IEnvironmentInfo.cs b/MediaBrowser.Model/System/IEnvironmentInfo.cs
deleted file mode 100644
index 3ffcc7de14..0000000000
--- a/MediaBrowser.Model/System/IEnvironmentInfo.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace MediaBrowser.Model.System
-{
-    public interface IEnvironmentInfo
-    {
-        OperatingSystem OperatingSystem { get; }
-        string OperatingSystemName { get; }
-        string OperatingSystemVersion { get; }
-        Architecture SystemArchitecture { get; }
-    }
-
-    public enum OperatingSystem
-    {
-        Windows,
-        Linux,
-        OSX,
-        BSD,
-        Android
-    }
-}
diff --git a/MediaBrowser.Model/System/OperatingSystemId.cs b/MediaBrowser.Model/System/OperatingSystemId.cs
new file mode 100644
index 0000000000..e81dd4213f
--- /dev/null
+++ b/MediaBrowser.Model/System/OperatingSystemId.cs
@@ -0,0 +1,10 @@
+namespace MediaBrowser.Model.System
+{
+    public enum OperatingSystemId
+    {
+        Windows,
+        Linux,
+        Darwin,
+        BSD
+    }
+}