Browse Source

Merge branch 'dev' into project-updates

Anthony Lavado 6 years ago
parent
commit
a06a5c8d18

+ 2 - 0
.gitignore

@@ -1,5 +1,7 @@
 !*
 
+.directory
+
 #################
 ## Eclipse
 #################

+ 7 - 6
CONTRIBUTORS.md

@@ -9,15 +9,16 @@
  - [bfayers](https://github.com/bfayers)
  - [Bond_009](https://github.com/Bond-009)
  - [AnthonyLavado](https://github.com/anthonylavado)
+ - [sparky8251](https://github.com/sparky8251)
 
 # Emby Contributors
 
- - [LukePulverenti](https://github.com/LukePulverenti) 
- - [ebr11](https://github.com/ebr11) 
- - [lalmanzar](https://github.com/lalmanzar) 
- - [schneifu](https://github.com/schneifu) 
- - [Mark2xv](https://github.com/Mark2xv) 
- - [ScottRapsey](https://github.com/ScottRapsey) 
+ - [LukePulverenti](https://github.com/LukePulverenti)
+ - [ebr11](https://github.com/ebr11)
+ - [lalmanzar](https://github.com/lalmanzar)
+ - [schneifu](https://github.com/schneifu)
+ - [Mark2xv](https://github.com/Mark2xv)
+ - [ScottRapsey](https://github.com/ScottRapsey)
  - [skynet600](https://github.com/skynet600)
  - [Cheesegeezer](https://githum.com/Cheesegeezer)
  - [Radeon](https://github.com/radeonorama)

+ 1 - 54
Emby.Server.Implementations/ApplicationHost.cs

@@ -368,7 +368,6 @@ namespace Emby.Server.Implementations
         protected IAuthService AuthService { get; private set; }
 
         public StartupOptions StartupOptions { get; private set; }
-        protected readonly string ReleaseAssetFilename;
 
         internal IPowerManagement PowerManagement { get; private set; }
         internal IImageEncoder ImageEncoder { get; private set; }
@@ -393,7 +392,6 @@ namespace Emby.Server.Implementations
             StartupOptions options,
             IFileSystem fileSystem,
             IPowerManagement powerManagement,
-            string releaseAssetFilename,
             IEnvironmentInfo environmentInfo,
             IImageEncoder imageEncoder,
             ISystemEvents systemEvents,
@@ -419,7 +417,6 @@ namespace Emby.Server.Implementations
             Logger = LoggerFactory.CreateLogger("App");
 
             StartupOptions = options;
-            ReleaseAssetFilename = releaseAssetFilename;
             PowerManagement = powerManagement;
 
             ImageEncoder = imageEncoder;
@@ -1240,7 +1237,7 @@ namespace Emby.Server.Implementations
                 HttpClient,
                 ZipClient,
                 ProcessFactory,
-                5000, false,
+                5000,
                 EnvironmentInfo);
 
             MediaEncoder = mediaEncoder;
@@ -2286,56 +2283,6 @@ namespace Emby.Server.Implementations
             Plugins = list.ToArray();
         }
 
-        /// <summary>
-        /// Checks for update.
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task{CheckForUpdateResult}.</returns>
-        public async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            var updateLevel = SystemUpdateLevel;
-            var cacheLength = updateLevel == PackageVersionClass.Release ?
-                TimeSpan.FromHours(12) :
-                TimeSpan.FromMinutes(5);
-
-            try
-            {
-                var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser",
-                    "Emby.Releases",
-                    ApplicationVersion,
-                    updateLevel,
-                    ReleaseAssetFilename,
-                    "MBServer",
-                    UpdateTargetFileName,
-                    cacheLength,
-                    cancellationToken).ConfigureAwait(false);
-
-                HasUpdateAvailable = result.IsUpdateAvailable;
-
-                return result;
-            }
-            catch (HttpException ex)
-            {
-                // users are overreacting to this occasionally failing
-                if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.Forbidden)
-                {
-                    HasUpdateAvailable = false;
-                    return new CheckForUpdateResult
-                    {
-                        IsUpdateAvailable = false
-                    };
-                }
-
-                throw;
-            }
-        }
-
-        protected virtual string UpdateTargetFileName
-        {
-            get { return "Mbserver.zip"; }
-        }
-
         /// <summary>
         /// Updates the application.
         /// </summary>

+ 2 - 2
Emby.Server.Implementations/Channels/ChannelManager.cs

@@ -901,8 +901,8 @@ namespace Emby.Server.Implementations.Channels
         private T GetItemById<T>(string idString, string channelName, out bool isNew)
             where T : BaseItem, new()
         {
-            var id = GetIdToHash(idString, channelName).GetMBId(typeof(T));
-
+            var id = _libraryManager.GetNewItemId(GetIdToHash(idString, channelName), typeof(T));
+ 
             T item = null;
 
             try

+ 2 - 1
Emby.Server.Implementations/Devices/DeviceManager.cs

@@ -145,7 +145,8 @@ namespace Emby.Server.Implementations.Devices
                 HasUser = true
 
             }).Items;
-
+            
+            // TODO: DeviceQuery doesn't seem to be used from client. Not even Swagger.
             if (query.SupportsSync.HasValue)
             {
                 var val = query.SupportsSync.Value;

+ 0 - 20
Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFile.cs

@@ -3380,26 +3380,6 @@ namespace SharpCifs.Smb
             SetAttributes(GetAttributes() & ~AttrReadonly);
         }
 
-        /// <summary>
-        /// Returns a
-        /// <see cref="System.Uri">System.Uri</see>
-        /// for this <code>SmbFile</code>. The
-        /// <code>URL</code> may be used as any other <code>URL</code> might to
-        /// access an SMB resource. Currently only retrieving data and information
-        /// is supported (i.e. no <tt>doOutput</tt>).
-        /// </summary>
-        /// <returns>
-        /// A new <code>
-        /// <see cref="System.Uri">System.Uri</see>
-        /// </code> for this <code>SmbFile</code>
-        /// </returns>
-        /// <exception cref="System.UriFormatException">System.UriFormatException</exception>
-        [Obsolete(@"Use getURL() instead")]
-        public virtual Uri ToUrl()
-        {
-            return Url;
-        }
-
         /// <summary>
         /// Computes a hashCode for this file based on the URL string and IP
         /// address if the server.

+ 2 - 104
Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs

@@ -189,7 +189,7 @@ namespace System.Net
         internal
 #endif
 
-            IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
+        IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
         {
 
             int maxCidr = family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
@@ -1164,18 +1164,6 @@ namespace System.Net
 
         }
 
-        [Obsolete("static Contains is deprecated, please use instance Contains.")]
-        public static bool Contains(IPNetwork network, IPAddress ipaddress)
-        {
-
-            if (network == null)
-            {
-                throw new ArgumentNullException("network");
-            }
-
-            return network.Contains(ipaddress);
-        }
-
         /// <summary>
         /// return true is network2 is fully contained in network
         /// </summary>
@@ -1201,18 +1189,6 @@ namespace System.Net
             return contains;
         }
 
-        [Obsolete("static Contains is deprecated, please use instance Contains.")]
-        public static bool Contains(IPNetwork network, IPNetwork network2)
-        {
-
-            if (network == null)
-            {
-                throw new ArgumentNullException("network");
-            }
-
-            return network.Contains(network2);
-        }
-
         #endregion
 
         #region overlap
@@ -1245,18 +1221,6 @@ namespace System.Net
             return overlap;
         }
 
-        [Obsolete("static Overlap is deprecated, please use instance Overlap.")]
-        public static bool Overlap(IPNetwork network, IPNetwork network2)
-        {
-
-            if (network == null)
-            {
-                throw new ArgumentNullException("network");
-            }
-
-            return network.Overlap(network2);
-        }
-
         #endregion
 
         #region ToString
@@ -1341,18 +1305,6 @@ namespace System.Net
                 || IPNetwork.IANA_CBLK_RESERVED1.Contains(this);
         }
 
-        [Obsolete("static IsIANAReserved is deprecated, please use instance IsIANAReserved.")]
-        public static bool IsIANAReserved(IPNetwork ipnetwork)
-        {
-
-            if (ipnetwork == null)
-            {
-                throw new ArgumentNullException("ipnetwork");
-            }
-
-            return ipnetwork.IsIANAReserved();
-        }
-
         #endregion
 
         #region Subnet
@@ -1371,16 +1323,6 @@ namespace System.Net
             return ipnetworkCollection;
         }
 
-        [Obsolete("static Subnet is deprecated, please use instance Subnet.")]
-        public static IPNetworkCollection Subnet(IPNetwork network, byte cidr)
-        {
-            if (network == null)
-            {
-                throw new ArgumentNullException("network");
-            }
-            return network.Subnet(cidr);
-        }
-
         /// <summary>
         /// Subnet a network into multiple nets of cidr mask
         /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
@@ -1402,16 +1344,6 @@ namespace System.Net
             return true;
         }
 
-        [Obsolete("static TrySubnet is deprecated, please use instance TrySubnet.")]
-        public static bool TrySubnet(IPNetwork network, byte cidr, out IPNetworkCollection ipnetworkCollection)
-        {
-            if (network == null)
-            {
-                throw new ArgumentNullException("network");
-            }
-            return network.TrySubnet(cidr, out ipnetworkCollection);
-        }
-
 #if TRAVISCI
         public
 #else
@@ -1476,12 +1408,6 @@ namespace System.Net
             return supernet;
         }
 
-        [Obsolete("static Supernet is deprecated, please use instance Supernet.")]
-        public static IPNetwork Supernet(IPNetwork network, IPNetwork network2)
-        {
-            return network.Supernet(network2);
-        }
-
         /// <summary>
         /// Try to supernet two consecutive cidr equal subnet into a single one
         /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23 
@@ -1500,16 +1426,6 @@ namespace System.Net
             return parsed;
         }
 
-        [Obsolete("static TrySupernet is deprecated, please use instance TrySupernet.")]
-        public static bool TrySupernet(IPNetwork network, IPNetwork network2, out IPNetwork supernet)
-        {
-            if (network == null)
-            {
-                throw new ArgumentNullException("network");
-            }
-            return network.TrySupernet(network2, out supernet);
-        }
-
 #if TRAVISCI
         public
 #else
@@ -1920,18 +1836,6 @@ namespace System.Net
             return sw.ToString();
         }
 
-        [Obsolete("static Print is deprecated, please use instance Print.")]
-        public static string Print(IPNetwork ipnetwork)
-        {
-
-            if (ipnetwork == null)
-            {
-                throw new ArgumentNullException("ipnetwork");
-            }
-
-            return ipnetwork.Print();
-        }
-
         #endregion
 
         #region TryGuessCidr
@@ -2018,12 +1922,6 @@ namespace System.Net
 
         #region ListIPAddress
 
-        [Obsolete("static ListIPAddress is deprecated, please use instance ListIPAddress.")]
-        public static IPAddressCollection ListIPAddress(IPNetwork ipnetwork)
-        {
-            return ipnetwork.ListIPAddress();
-        }
-
         public IPAddressCollection ListIPAddress()
         {
             return new IPAddressCollection(this);
@@ -2167,4 +2065,4 @@ namespace System.Net
         #endregion
 
     }
-}
+}

+ 0 - 142
Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs

@@ -1,142 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Common.Updates;
-using Microsoft.Extensions.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.ScheduledTasks
-{
-    /// <summary>
-    /// Plugin Update Task
-    /// </summary>
-    public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
-    {
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
-
-        private readonly IInstallationManager _installationManager;
-
-        private readonly IApplicationHost _appHost;
-
-        public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
-        {
-            _logger = logger;
-            _installationManager = installationManager;
-            _appHost = appHost;
-        }
-
-        /// <summary>
-        /// Creates the triggers that define when the task will run
-        /// </summary>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
-        {
-            return new[] { 
-            
-                // At startup
-                new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
-
-                // Every so often
-                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
-            };
-        }
-
-        public string Key
-        {
-            get { return "PluginUpdates"; }
-        }
-
-        /// <summary>
-        /// Update installed plugins
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task.</returns>
-        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            progress.Report(0);
-
-            var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, true, cancellationToken).ConfigureAwait(false)).ToList();
-
-            progress.Report(10);
-
-            var numComplete = 0;
-
-            foreach (var package in packagesToInstall)
-            {
-                cancellationToken.ThrowIfCancellationRequested();
-
-                try
-                {
-                    await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
-                }
-                catch (OperationCanceledException)
-                {
-                    // InstallPackage has it's own inner cancellation token, so only throw this if it's ours
-                    if (cancellationToken.IsCancellationRequested)
-                    {
-                        throw;
-                    }
-                }
-                catch (HttpException ex)
-                {
-                    _logger.LogError(ex, "Error downloading {name}", package.name);
-                }
-                catch (IOException ex)
-                {
-                    _logger.LogError(ex, "Error updating {name}", package.name);
-                }
-
-                // Update progress
-                lock (progress)
-                {
-                    numComplete++;
-                    double percent = numComplete;
-                    percent /= packagesToInstall.Count;
-
-                    progress.Report(90 * percent + 10);
-                }
-            }
-
-            progress.Report(100);
-        }
-
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get { return "Check for plugin updates"; }
-        }
-
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
-        public string Description
-        {
-            get { return "Downloads and installs updates for plugins that are configured to update automatically."; }
-        }
-
-        public string Category
-        {
-            get { return "Application"; }
-        }
-
-        public bool IsHidden => true;
-
-        public bool IsEnabled => true;
-
-        public bool IsLogged => true;
-    }
-}

+ 0 - 128
Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs

@@ -1,128 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Common.Configuration;
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.ScheduledTasks
-{
-    /// <summary>
-    /// Plugin Update Task
-    /// </summary>
-    public class SystemUpdateTask : IScheduledTask
-    {
-        /// <summary>
-        /// The _app host
-        /// </summary>
-        private readonly IApplicationHost _appHost;
-
-        /// <summary>
-        /// Gets or sets the configuration manager.
-        /// </summary>
-        /// <value>The configuration manager.</value>
-        private IConfigurationManager ConfigurationManager { get; set; }
-        /// <summary>
-        /// Gets or sets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
-        private ILogger Logger { get; set; }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SystemUpdateTask" /> class.
-        /// </summary>
-        /// <param name="appHost">The app host.</param>
-        /// <param name="configurationManager">The configuration manager.</param>
-        /// <param name="logger">The logger.</param>
-        public SystemUpdateTask(IApplicationHost appHost, IConfigurationManager configurationManager, ILogger logger)
-        {
-            _appHost = appHost;
-            ConfigurationManager = configurationManager;
-            Logger = logger;
-        }
-
-        /// <summary>
-        /// Creates the triggers that define when the task will run
-        /// </summary>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
-        {
-            return new[] { 
-            
-                // At startup
-                new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
-
-                // Every so often
-                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
-            };
-        }
-
-        /// <summary>
-        /// Returns the task to be executed
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task.</returns>
-        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            // Create a progress object for the update check
-            var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, new SimpleProgress<double>()).ConfigureAwait(false);
-
-            if (!updateInfo.IsUpdateAvailable)
-            {
-                Logger.LogDebug("No application update available.");
-                return;
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            if (!_appHost.CanSelfUpdate) return;
-
-            if (ConfigurationManager.CommonConfiguration.EnableAutoUpdate)
-            {
-                Logger.LogInformation("Update Revision {0} available.  Updating...", updateInfo.AvailableVersion);
-
-                await _appHost.UpdateApplication(updateInfo.Package, cancellationToken, progress).ConfigureAwait(false);
-            }
-            else
-            {
-                Logger.LogInformation("A new version of " + _appHost.Name + " is available.");
-            }
-        }
-
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get { return "Check for application updates"; }
-        }
-
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
-        public string Description
-        {
-            get { return "Downloads and installs application updates."; }
-        }
-
-        /// <summary>
-        /// Gets the category.
-        /// </summary>
-        /// <value>The category.</value>
-        public string Category
-        {
-            get { return "Application"; }
-        }
-
-        public string Key
-        {
-            get { return "SystemUpdateTask"; }
-        }
-    }
-}

+ 2 - 2
Jellyfin.Server/CoreAppHost.cs

@@ -11,8 +11,8 @@ namespace Jellyfin.Server
 {
     public class CoreAppHost : ApplicationHost
     {
-        public CoreAppHost(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager)
-            : base(applicationPaths, loggerFactory, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager)
+        public CoreAppHost(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager)
+            : base(applicationPaths, loggerFactory, options, fileSystem, powerManagement, environmentInfo, imageEncoder, systemEvents, networkManager)
         {
         }
 

+ 0 - 1
Jellyfin.Server/Program.cs

@@ -73,7 +73,6 @@ namespace Jellyfin.Server
                 options,
                 fileSystem,
                 new PowerManagement(),
-                "embyserver-mono_{version}.zip",
                 environmentInfo,
                 new NullImageEncoder(),
                 new SystemEvents(_loggerFactory.CreateLogger("SystemEvents")),

+ 0 - 20
MediaBrowser.Common/Extensions/BaseExtensions.cs

@@ -34,25 +34,5 @@ namespace MediaBrowser.Common.Extensions
         {
             return CryptographyProvider.GetMD5(str);
         }
-
-        /// <summary>
-        /// Gets the MB id.
-        /// </summary>
-        /// <param name="str">The STR.</param>
-        /// <param name="type">The type.</param>
-        /// <returns>Guid.</returns>
-        /// <exception cref="System.ArgumentNullException">type</exception>
-        [Obsolete("Use LibraryManager.GetNewItemId")]
-        public static Guid GetMBId(this string str, Type type)
-        {
-            if (type == null)
-            {
-                throw new ArgumentNullException("type");
-            }
-
-            var key = type.FullName + str.ToLower();
-
-            return key.GetMD5();
-        }
     }
 }

+ 0 - 6
MediaBrowser.Common/IApplicationHost.cs

@@ -85,12 +85,6 @@ namespace MediaBrowser.Common
         /// <returns>IEnumerable{``0}.</returns>
         IEnumerable<T> GetExports<T>(bool manageLiftime = true);
 
-        /// <summary>
-        /// Checks for update.
-        /// </summary>
-        /// <returns>Task{CheckForUpdateResult}.</returns>
-        Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress);
-
         /// <summary>
         /// Updates the application.
         /// </summary>

+ 0 - 274
MediaBrowser.Common/Updates/GithubUpdater.cs

@@ -1,274 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Updates;
-
-namespace MediaBrowser.Common.Updates
-{
-    public class GithubUpdater
-    {
-        private readonly IHttpClient _httpClient;
-        private readonly IJsonSerializer _jsonSerializer;
-
-        public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer)
-        {
-            _httpClient = httpClient;
-            _jsonSerializer = jsonSerializer;
-        }
-
-        public async Task<CheckForUpdateResult> CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, TimeSpan cacheLength, CancellationToken cancellationToken)
-        {
-            var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
-
-            var options = new HttpRequestOptions
-            {
-                Url = url,
-                EnableKeepAlive = false,
-                CancellationToken = cancellationToken,
-                UserAgent = "Emby/3.0",
-                BufferContent = false
-            };
-
-            if (cacheLength.Ticks > 0)
-            {
-                options.CacheMode = CacheMode.Unconditional;
-                options.CacheLength = cacheLength;
-            }
-
-            using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
-            using (var stream = response.Content)
-            {
-                var obj = await _jsonSerializer.DeserializeFromStreamAsync<RootObject[]>(stream).ConfigureAwait(false);
-
-                return CheckForUpdateResult(obj, minVersion, updateLevel, assetFilename, packageName, targetFilename);
-            }
-        }
-
-        private CheckForUpdateResult CheckForUpdateResult(RootObject[] obj, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename)
-        {
-            if (updateLevel == PackageVersionClass.Release)
-            {
-                // Technically all we need to do is check that it's not pre-release
-                // But let's addititional checks for -beta and -dev to handle builds that might be temporarily tagged incorrectly.
-                obj = obj.Where(i => !i.prerelease && !i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) && !i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
-            }
-            else if (updateLevel == PackageVersionClass.Beta)
-            {
-                obj = obj.Where(i => i.prerelease && i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase)).ToArray();
-            }
-            else if (updateLevel == PackageVersionClass.Dev)
-            {
-                obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) || i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray();
-            }
-
-            var availableUpdate = obj
-                .Select(i => CheckForUpdateResult(i, minVersion, assetFilename, packageName, targetFilename))
-                .Where(i => i != null)
-                .OrderByDescending(i => Version.Parse(i.AvailableVersion))
-                .FirstOrDefault();
-
-            return availableUpdate ?? new CheckForUpdateResult
-            {
-                IsUpdateAvailable = false
-            };
-        }
-
-        private bool MatchesUpdateLevel(RootObject i, PackageVersionClass updateLevel)
-        {
-            if (updateLevel == PackageVersionClass.Beta)
-            {
-                return i.prerelease && i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase);
-            }
-            if (updateLevel == PackageVersionClass.Dev)
-            {
-                return !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) ||
-                       i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase);
-            }
-
-            // Technically all we need to do is check that it's not pre-release
-            // But let's addititional checks for -beta and -dev to handle builds that might be temporarily tagged incorrectly.
-            return !i.prerelease && !i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) &&
-                   !i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase);
-        }
-
-        public async Task<List<RootObject>> GetLatestReleases(string organzation, string repository, string assetFilename, CancellationToken cancellationToken)
-        {
-            var list = new List<RootObject>();
-
-            var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository);
-
-            var options = new HttpRequestOptions
-            {
-                Url = url,
-                EnableKeepAlive = false,
-                CancellationToken = cancellationToken,
-                UserAgent = "Emby/3.0",
-                BufferContent = false
-            };
-
-            using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
-            using (var stream = response.Content)
-            {
-                var obj = await _jsonSerializer.DeserializeFromStreamAsync<RootObject[]>(stream).ConfigureAwait(false);
-
-                obj = obj.Where(i => (i.assets ?? new List<Asset>()).Any(a => IsAsset(a, assetFilename, i.tag_name))).ToArray();
-
-                list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Release)).OrderByDescending(GetVersion).Take(1));
-                list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Beta)).OrderByDescending(GetVersion).Take(1));
-                list.AddRange(obj.Where(i => MatchesUpdateLevel(i, PackageVersionClass.Dev)).OrderByDescending(GetVersion).Take(1));
-
-                return list;
-            }
-        }
-
-        public Version GetVersion(RootObject obj)
-        {
-            Version version;
-            if (!Version.TryParse(obj.tag_name, out version))
-            {
-                return new Version(1, 0);
-            }
-
-            return version;
-        }
-
-        private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename)
-        {
-            Version version;
-            var versionString = obj.tag_name;
-            if (!Version.TryParse(versionString, out version))
-            {
-                return null;
-            }
-
-            if (version < minVersion)
-            {
-                return null;
-            }
-
-            var asset = (obj.assets ?? new List<Asset>()).FirstOrDefault(i => IsAsset(i, assetFilename, versionString));
-
-            if (asset == null)
-            {
-                return null;
-            }
-
-            return new CheckForUpdateResult
-            {
-                AvailableVersion = version.ToString(),
-                IsUpdateAvailable = version > minVersion,
-                Package = new PackageVersionInfo
-                {
-                    classification = obj.prerelease ?
-                        (obj.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase) ? PackageVersionClass.Dev : PackageVersionClass.Beta) :
-                        PackageVersionClass.Release,
-                    name = packageName,
-                    sourceUrl = asset.browser_download_url,
-                    targetFilename = targetFilename,
-                    versionStr = version.ToString(),
-                    requiredVersionStr = "1.0.0",
-                    description = obj.body,
-                    infoUrl = obj.html_url
-                }
-            };
-        }
-
-        private bool IsAsset(Asset asset, string assetFilename, string version)
-        {
-            var downloadFilename = Path.GetFileName(asset.browser_download_url) ?? string.Empty;
-
-            assetFilename = assetFilename.Replace("{version}", version);
-
-            if (downloadFilename.IndexOf(assetFilename, StringComparison.OrdinalIgnoreCase) != -1)
-            {
-                return true;
-            }
-
-            return string.Equals(assetFilename, downloadFilename, StringComparison.OrdinalIgnoreCase);
-        }
-
-        public class Uploader
-        {
-            public string login { get; set; }
-            public int id { get; set; }
-            public string avatar_url { get; set; }
-            public string gravatar_id { get; set; }
-            public string url { get; set; }
-            public string html_url { get; set; }
-            public string followers_url { get; set; }
-            public string following_url { get; set; }
-            public string gists_url { get; set; }
-            public string starred_url { get; set; }
-            public string subscriptions_url { get; set; }
-            public string organizations_url { get; set; }
-            public string repos_url { get; set; }
-            public string events_url { get; set; }
-            public string received_events_url { get; set; }
-            public string type { get; set; }
-            public bool site_admin { get; set; }
-        }
-
-        public class Asset
-        {
-            public string url { get; set; }
-            public int id { get; set; }
-            public string name { get; set; }
-            public object label { get; set; }
-            public Uploader uploader { get; set; }
-            public string content_type { get; set; }
-            public string state { get; set; }
-            public int size { get; set; }
-            public int download_count { get; set; }
-            public string created_at { get; set; }
-            public string updated_at { get; set; }
-            public string browser_download_url { get; set; }
-        }
-
-        public class Author
-        {
-            public string login { get; set; }
-            public int id { get; set; }
-            public string avatar_url { get; set; }
-            public string gravatar_id { get; set; }
-            public string url { get; set; }
-            public string html_url { get; set; }
-            public string followers_url { get; set; }
-            public string following_url { get; set; }
-            public string gists_url { get; set; }
-            public string starred_url { get; set; }
-            public string subscriptions_url { get; set; }
-            public string organizations_url { get; set; }
-            public string repos_url { get; set; }
-            public string events_url { get; set; }
-            public string received_events_url { get; set; }
-            public string type { get; set; }
-            public bool site_admin { get; set; }
-        }
-
-        public class RootObject
-        {
-            public string url { get; set; }
-            public string assets_url { get; set; }
-            public string upload_url { get; set; }
-            public string html_url { get; set; }
-            public int id { get; set; }
-            public string tag_name { get; set; }
-            public string target_commitish { get; set; }
-            public string name { get; set; }
-            public bool draft { get; set; }
-            public Author author { get; set; }
-            public bool prerelease { get; set; }
-            public string created_at { get; set; }
-            public string published_at { get; set; }
-            public List<Asset> assets { get; set; }
-            public string tarball_url { get; set; }
-            public string zipball_url { get; set; }
-            public string body { get; set; }
-        }
-    }
-}

+ 40 - 64
MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs

@@ -1,7 +1,8 @@
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
 using MediaBrowser.Model.Diagnostics;
 using Microsoft.Extensions.Logging;
 
@@ -18,21 +19,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
             _processFactory = processFactory;
         }
 
-        public Tuple<List<string>, List<string>> Validate(string encoderPath)
+        public (IEnumerable<string> decoders, IEnumerable<string> encoders) Validate(string encoderPath)
         {
-            _logger.LogInformation("Validating media encoder at {0}", encoderPath);
+            _logger.LogInformation("Validating media encoder at {EncoderPath}", encoderPath);
 
-            var decoders = GetDecoders(encoderPath);
-            var encoders = GetEncoders(encoderPath);
+            var decoders = GetCodecs(encoderPath, Codec.Decoder);
+            var encoders = GetCodecs(encoderPath, Codec.Encoder);
 
             _logger.LogInformation("Encoder validation complete");
 
-            return new Tuple<List<string>, List<string>>(decoders, encoders);
+            return (decoders, encoders);
         }
 
         public bool ValidateVersion(string encoderAppPath, bool logOutput)
         {
-            string output = string.Empty;
+            string output = null;
             try
             {
                 output = GetProcessOutput(encoderAppPath, "-version");
@@ -71,20 +72,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return true;
         }
 
-        private List<string> GetDecoders(string encoderAppPath)
-        {
-            string output = string.Empty;
-            try
-            {
-                output = GetProcessOutput(encoderAppPath, "-decoders");
-            }
-            catch (Exception ex)
-            {
-                _logger.LogError(ex, "Error detecting available decoders");
-            }
-
-            var found = new List<string>();
-            var required = new[]
+        private static readonly string[] requiredDecoders = new[]
             {
                 "mpeg2video",
                 "h264_qsv",
@@ -101,33 +89,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 "hevc"
             };
 
-            foreach (var codec in required)
-            {
-                var srch = " " + codec + "  ";
-
-                if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) != -1)
-                {
-                    _logger.LogInformation("Decoder available: " + codec);
-                    found.Add(codec);
-                }
-            }
-
-            return found;
-        }
-
-        private List<string> GetEncoders(string encoderAppPath)
-        {
-            string output = null;
-            try
-            {
-                output = GetProcessOutput(encoderAppPath, "-encoders");
-            }
-            catch
-            {
-            }
-
-            var found = new List<string>();
-            var required = new[]
+        private static readonly string[] requiredEncoders = new[]
             {
                 "libx264",
                 "libx265",
@@ -151,32 +113,46 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 "ac3"
             };
 
-            output = output ?? string.Empty;
+        private enum Codec
+        {
+            Encoder,
+            Decoder
+        }
 
-            var index = 0;
+        private IEnumerable<string> GetCodecs(string encoderAppPath, Codec codec)
+        {
+            string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
+            string output = null;
+            try
+            {
+                output = GetProcessOutput(encoderAppPath, "-" + codecstr);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error detecting available {Codec}", codecstr);
+            }
 
-            foreach (var codec in required)
+            if (string.IsNullOrWhiteSpace(output))
             {
-                var srch = " " + codec + "  ";
+                return Enumerable.Empty<string>();
+            }
 
-                if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) != -1)
-                {
-                    if (index < required.Length - 1)
-                    {
-                        _logger.LogInformation("Encoder available: " + codec);
-                    }
+            var required = codec == Codec.Encoder ? requiredEncoders : requiredDecoders;
 
-                    found.Add(codec);
-                }
-                index++;
-            }
+            var found = Regex
+                .Matches(output, @"^\s\S{6}\s(?<codec>[\w|-]+)\s+.+$", RegexOptions.Multiline)
+                .Cast<Match>()
+                .Select(x => x.Groups["codec"].Value)
+                .Where(x => required.Contains(x));
+
+            _logger.LogInformation("Available {Codec}: {Codecs}", codecstr, found);
 
             return found;
         }
 
         private string GetProcessOutput(string path, string arguments)
         {
-            var process = _processFactory.Create(new ProcessOptions
+            IProcess process = _processFactory.Create(new ProcessOptions
             {
                 CreateNoWindow = true,
                 UseShellExecute = false,
@@ -187,7 +163,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 RedirectStandardOutput = true
             });
 
-            _logger.LogInformation("Running {path} {arguments}", path, arguments);
+            _logger.LogInformation("Running {Path} {Arguments}", path, arguments);
 
             using (process)
             {

+ 0 - 179
MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs

@@ -1,179 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
-    public class FontConfigLoader
-    {
-        private readonly IHttpClient _httpClient;
-        private readonly IApplicationPaths _appPaths;
-        private readonly ILogger _logger;
-        private readonly IZipClient _zipClient;
-        private readonly IFileSystem _fileSystem;
-
-        private readonly string[] _fontUrls =
-        {
-            "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/ARIALUNI.7z"
-        };
-
-        public FontConfigLoader(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, IZipClient zipClient, IFileSystem fileSystem)
-        {
-            _httpClient = httpClient;
-            _appPaths = appPaths;
-            _logger = logger;
-            _zipClient = zipClient;
-            _fileSystem = fileSystem;
-        }
-
-        /// <summary>
-        /// Extracts the fonts.
-        /// </summary>
-        /// <param name="targetPath">The target path.</param>
-        /// <returns>Task.</returns>
-        public async Task DownloadFonts(string targetPath)
-        {
-            try
-            {
-                var fontsDirectory = Path.Combine(targetPath, "fonts");
-
-                _fileSystem.CreateDirectory(fontsDirectory);
-
-                const string fontFilename = "ARIALUNI.TTF";
-
-                var fontFile = Path.Combine(fontsDirectory, fontFilename);
-
-                if (_fileSystem.FileExists(fontFile))
-                {
-                    await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
-                }
-                else
-                {
-                    // Kick this off, but no need to wait on it
-                    var task = Task.Run(async () =>
-                    {
-                        await DownloadFontFile(fontsDirectory, fontFilename, new SimpleProgress<double>()).ConfigureAwait(false);
-
-                        await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
-                    });
-                }
-            }
-            catch (HttpException ex)
-            {
-                // Don't let the server crash because of this
-                _logger.LogError(ex, "Error downloading ffmpeg font files");
-            }
-            catch (Exception ex)
-            {
-                // Don't let the server crash because of this
-                _logger.LogError(ex, "Error writing ffmpeg font files");
-            }
-        }
-
-        /// <summary>
-        /// Downloads the font file.
-        /// </summary>
-        /// <param name="fontsDirectory">The fonts directory.</param>
-        /// <param name="fontFilename">The font filename.</param>
-        /// <returns>Task.</returns>
-        private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress)
-        {
-            var existingFile = _fileSystem
-                .GetFilePaths(_appPaths.ProgramDataPath, true)
-                .FirstOrDefault(i => string.Equals(fontFilename, Path.GetFileName(i), StringComparison.OrdinalIgnoreCase));
-
-            if (existingFile != null)
-            {
-                try
-                {
-                    _fileSystem.CopyFile(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
-                    return;
-                }
-                catch (IOException ex)
-                {
-                    // Log this, but don't let it fail the operation
-                    _logger.LogError(ex, "Error copying file");
-                }
-            }
-
-            string tempFile = null;
-
-            foreach (var url in _fontUrls)
-            {
-                progress.Report(0);
-
-                try
-                {
-                    tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
-                    {
-                        Url = url,
-                        Progress = progress
-
-                    }).ConfigureAwait(false);
-
-                    break;
-                }
-                catch (Exception ex)
-                {
-                    // The core can function without the font file, so handle this
-                    _logger.LogError(ex, "Failed to download ffmpeg font file from {url}", url);
-                }
-            }
-
-            if (string.IsNullOrEmpty(tempFile))
-            {
-                return;
-            }
-
-            Extract7zArchive(tempFile, fontsDirectory);
-
-            try
-            {
-                _fileSystem.DeleteFile(tempFile);
-            }
-            catch (IOException ex)
-            {
-                // Log this, but don't let it fail the operation
-                _logger.LogError(ex, "Error deleting temp file {path}", tempFile);
-            }
-        }
-        private void Extract7zArchive(string archivePath, string targetPath)
-        {
-            _logger.LogInformation("Extracting {ArchivePath} to {TargetPath}", archivePath, targetPath);
-
-            _zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
-        }
-
-        /// <summary>
-        /// Writes the font config file.
-        /// </summary>
-        /// <param name="fontsDirectory">The fonts directory.</param>
-        /// <returns>Task.</returns>
-        private async Task WriteFontConfigFile(string fontsDirectory)
-        {
-            const string fontConfigFilename = "fonts.conf";
-            var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
-
-            if (!_fileSystem.FileExists(fontConfigFile))
-            {
-                var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
-
-                var bytes = Encoding.UTF8.GetBytes(contents);
-
-                using (var fileStream = _fileSystem.GetFileStream(fontConfigFile, FileOpenMode.Create, FileAccessMode.Write,
-                                                    FileShareMode.Read, true))
-                {
-                    await fileStream.WriteAsync(bytes, 0, bytes.Length);
-                }
-            }
-        }
-    }
-}

+ 22 - 19
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -70,13 +70,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
         private readonly string _originalFFMpegPath;
         private readonly string _originalFFProbePath;
         private readonly int DefaultImageExtractionTimeoutMs;
-        private readonly bool EnableEncoderFontFile;
-
         private readonly IEnvironmentInfo _environmentInfo;
 
-        public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IProcessFactory processFactory,
+        public MediaEncoder(ILogger logger,
+            IJsonSerializer jsonSerializer,
+            string ffMpegPath,
+            string ffProbePath,
+            bool hasExternalEncoder,
+            IServerConfigurationManager configurationManager,
+            IFileSystem fileSystem,
+            ILiveTvManager liveTvManager,
+            IIsoManager isoManager,
+            ILibraryManager libraryManager,
+            IChannelManager channelManager,
+            ISessionManager sessionManager,
+            Func<ISubtitleEncoder> subtitleEncoder,
+            Func<IMediaSourceManager> mediaSourceManager,
+            IHttpClient httpClient,
+            IZipClient zipClient,
+            IProcessFactory processFactory,
             int defaultImageExtractionTimeoutMs,
-            bool enableEncoderFontFile, IEnvironmentInfo environmentInfo)
+            IEnvironmentInfo environmentInfo)
         {
             _logger = logger;
             _jsonSerializer = jsonSerializer;
@@ -93,7 +107,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
             _zipClient = zipClient;
             _processFactory = processFactory;
             DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs;
-            EnableEncoderFontFile = enableEncoderFontFile;
             _environmentInfo = environmentInfo;
             FFProbePath = ffProbePath;
             FFMpegPath = ffMpegPath;
@@ -175,18 +188,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
             {
                 var result = new EncoderValidator(_logger, _processFactory).Validate(FFMpegPath);
 
-                SetAvailableDecoders(result.Item1);
-                SetAvailableEncoders(result.Item2);
-
-                if (EnableEncoderFontFile)
-                {
-                    var directory = FileSystem.GetDirectoryName(FFMpegPath);
-
-                    if (!string.IsNullOrWhiteSpace(directory) && FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.ProgramDataPath, directory))
-                    {
-                        new FontConfigLoader(_httpClient, ConfigurationManager.ApplicationPaths, _logger, _zipClient, FileSystem).DownloadFonts(directory).ConfigureAwait(false);
-                    }
-                }
+                SetAvailableDecoders(result.decoders);
+                SetAvailableEncoders(result.encoders);
             }
         }
 
@@ -401,14 +404,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
         }
 
         private List<string> _encoders = new List<string>();
-        public void SetAvailableEncoders(List<string> list)
+        public void SetAvailableEncoders(IEnumerable<string> list)
         {
             _encoders = list.ToList();
             //_logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray()));
         }
 
         private List<string> _decoders = new List<string>();
-        public void SetAvailableDecoders(List<string> list)
+        public void SetAvailableDecoders(IEnumerable<string> list)
         {
             _decoders = list.ToList();
             //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray()));

+ 3 - 1
MediaBrowser.Model/Devices/DeviceQuery.cs

@@ -1,4 +1,6 @@
 
+using System;
+
 namespace MediaBrowser.Model.Devices
 {
     public class DeviceQuery
@@ -17,6 +19,6 @@ namespace MediaBrowser.Model.Devices
         /// Gets or sets the user identifier.
         /// </summary>
         /// <value>The user identifier.</value>
-        public string UserId { get; set; }
+        public Guid UserId { get; set; }
     }
 }