Forráskód Böngészése

Improve IInstallationManager interface

Bond_009 5 éve
szülő
commit
d529f81cd9

+ 1 - 1
Emby.Dlna/PlayTo/PlayToManager.cs

@@ -160,7 +160,7 @@ namespace Emby.Dlna.PlayTo
                 uuid = location.GetMD5().ToString("N", CultureInfo.InvariantCulture);
                 uuid = location.GetMD5().ToString("N", CultureInfo.InvariantCulture);
             }
             }
 
 
-            var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersion, uuid, null, uri.OriginalString, null);
+            var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersionString, uuid, null, uri.OriginalString, null);
 
 
             var controller = sessionInfo.SessionControllers.OfType<PlayToController>().FirstOrDefault();
             var controller = sessionInfo.SessionControllers.OfType<PlayToController>().FirstOrDefault();
 
 

+ 8 - 4
Emby.Server.Implementations/ApplicationHost.cs

@@ -410,13 +410,17 @@ namespace Emby.Server.Implementations
             _validAddressResults.Clear();
             _validAddressResults.Clear();
         }
         }
 
 
-        public string ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
+        /// <inheritdoc />
+        public Version ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version;
+
+        /// <inheritdoc />
+        public string ApplicationVersionString { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
 
 
         /// <summary>
         /// <summary>
         /// Gets the current application user agent.
         /// Gets the current application user agent.
         /// </summary>
         /// </summary>
         /// <value>The application user agent.</value>
         /// <value>The application user agent.</value>
-        public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersion;
+        public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersionString;
 
 
         /// <summary>
         /// <summary>
         /// Gets the email address for use within a comment section of a user agent field.
         /// Gets the email address for use within a comment section of a user agent field.
@@ -1425,7 +1429,7 @@ namespace Emby.Server.Implementations
             {
             {
                 HasPendingRestart = HasPendingRestart,
                 HasPendingRestart = HasPendingRestart,
                 IsShuttingDown = IsShuttingDown,
                 IsShuttingDown = IsShuttingDown,
-                Version = ApplicationVersion,
+                Version = ApplicationVersionString,
                 WebSocketPortNumber = HttpPort,
                 WebSocketPortNumber = HttpPort,
                 CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
                 CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
                 Id = SystemId,
                 Id = SystemId,
@@ -1465,7 +1469,7 @@ namespace Emby.Server.Implementations
 
 
             return new PublicSystemInfo
             return new PublicSystemInfo
             {
             {
-                Version = ApplicationVersion,
+                Version = ApplicationVersionString,
                 ProductName = ApplicationProductName,
                 ProductName = ApplicationProductName,
                 Id = SystemId,
                 Id = SystemId,
                 OperatingSystem = OperatingSystem.Id.ToString(),
                 OperatingSystem = OperatingSystem.Id.ToString(),

+ 15 - 9
Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs

@@ -1,24 +1,23 @@
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Model.Net;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using MediaBrowser.Common.Progress;
+using MediaBrowser.Common.Updates;
+using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks
 namespace Emby.Server.Implementations.ScheduledTasks
 {
 {
     /// <summary>
     /// <summary>
-    /// Plugin Update Task
+    /// Plugin Update Task.
     /// </summary>
     /// </summary>
     public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
     public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
     {
     {
         /// <summary>
         /// <summary>
-        /// The _logger
+        /// The _logger.
         /// </summary>
         /// </summary>
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
@@ -31,7 +30,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Creates the triggers that define when the task will run
+        /// Creates the triggers that define when the task will run.
         /// </summary>
         /// </summary>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
         /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
         public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
         public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
@@ -44,16 +43,16 @@ namespace Emby.Server.Implementations.ScheduledTasks
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Update installed plugins
+        /// Update installed plugins.
         /// </summary>
         /// </summary>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <param name="progress">The progress.</param>
-        /// <returns>Task.</returns>
+        /// <returns><see cref="Task" />.</returns>
         public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
             progress.Report(0);
             progress.Report(0);
 
 
-            var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(typeof(PluginUpdateTask).Assembly.GetName().Version, true, cancellationToken).ConfigureAwait(false)).ToList();
+            var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(cancellationToken).ConfigureAwait(false)).ToList();
 
 
             progress.Report(10);
             progress.Report(10);
 
 
@@ -94,18 +93,25 @@ namespace Emby.Server.Implementations.ScheduledTasks
             progress.Report(100);
             progress.Report(100);
         }
         }
 
 
+        /// <inheritdoc />
         public string Name => "Check for plugin updates";
         public string Name => "Check for plugin updates";
 
 
+        /// <inheritdoc />
         public string Description => "Downloads and installs updates for plugins that are configured to update automatically.";
         public string Description => "Downloads and installs updates for plugins that are configured to update automatically.";
 
 
+        /// <inheritdoc />
         public string Category => "Application";
         public string Category => "Application";
 
 
+        /// <inheritdoc />
         public string Key => "PluginUpdates";
         public string Key => "PluginUpdates";
 
 
+        /// <inheritdoc />
         public bool IsHidden => false;
         public bool IsHidden => false;
 
 
+        /// <inheritdoc />
         public bool IsEnabled => true;
         public bool IsEnabled => true;
 
 
+        /// <inheritdoc />
         public bool IsLogged => true;
         public bool IsLogged => true;
     }
     }
 }
 }

+ 53 - 159
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -107,26 +107,8 @@ namespace Emby.Server.Implementations.Updates
             _zipClient = zipClient;
             _zipClient = zipClient;
         }
         }
 
 
-        /// <summary>
-        /// Gets all available packages.
-        /// </summary>
-        /// <returns>Task{List{PackageInfo}}.</returns>
-        public async Task<List<PackageInfo>> GetAvailablePackages(
-            CancellationToken cancellationToken,
-            bool withRegistration = true,
-            string packageType = null,
-            Version applicationVersion = null)
-        {
-            var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
-            return FilterPackages(packages, packageType, applicationVersion);
-        }
-
-        /// <summary>
-        /// Gets all available packages.
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{List{PackageInfo}}.</returns>
-        public async Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken)
+        /// <inheritdoc />
+        public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default)
         {
         {
             using (var response = await _httpClient.SendAsync(
             using (var response = await _httpClient.SendAsync(
                 new HttpRequestOptions
                 new HttpRequestOptions
@@ -134,178 +116,89 @@ namespace Emby.Server.Implementations.Updates
                     Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
                     Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
                     CancellationToken = cancellationToken,
                     CancellationToken = cancellationToken,
                     CacheMode = CacheMode.Unconditional,
                     CacheMode = CacheMode.Unconditional,
-                    CacheLength = GetCacheLength()
+                    CacheLength = TimeSpan.FromMinutes(3)
                 },
                 },
                 HttpMethod.Get).ConfigureAwait(false))
                 HttpMethod.Get).ConfigureAwait(false))
             using (Stream stream = response.Content)
             using (Stream stream = response.Content)
             {
             {
-                return FilterPackages(await _jsonSerializer.DeserializeFromStreamAsync<PackageInfo[]>(stream).ConfigureAwait(false));
+                return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>(
+                    stream).ConfigureAwait(false);
             }
             }
         }
         }
 
 
-        private static TimeSpan GetCacheLength()
-        {
-            return TimeSpan.FromMinutes(3);
-        }
-
-        protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages)
+        /// <inheritdoc />
+        public IEnumerable<PackageInfo> FilterPackages(
+            IEnumerable<PackageInfo> availablePackages,
+            string name = null,
+            Guid guid = default)
         {
         {
-            var list = new List<PackageInfo>();
-
-            foreach (var package in packages)
+            if (name != null)
             {
             {
-                var versions = new List<PackageVersionInfo>();
-                foreach (var version in package.versions)
-                {
-                    if (string.IsNullOrEmpty(version.sourceUrl))
-                    {
-                        continue;
-                    }
-
-                    versions.Add(version);
-                }
-
-                package.versions = versions
-                    .OrderByDescending(x => x.Version)
-                    .ToArray();
-
-                if (package.versions.Length == 0)
-                {
-                    continue;
-                }
-
-                list.Add(package);
+                availablePackages = availablePackages.Where(x => x.name.Equals(name, StringComparison.OrdinalIgnoreCase));
             }
             }
 
 
-            // Remove packages with no versions
-            return list;
-        }
-
-        protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages, string packageType, Version applicationVersion)
-        {
-            var packagesList = FilterPackages(packages);
-
-            var returnList = new List<PackageInfo>();
-
-            var filterOnPackageType = !string.IsNullOrEmpty(packageType);
-
-            foreach (var p in packagesList)
+            if (guid != Guid.Empty)
             {
             {
-                if (filterOnPackageType && !string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase))
-                {
-                    continue;
-                }
-
-                // If an app version was supplied, filter the versions for each package to only include supported versions
-                if (applicationVersion != null)
-                {
-                    p.versions = p.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToArray();
-                }
-
-                if (p.versions.Length == 0)
-                {
-                    continue;
-                }
-
-                returnList.Add(p);
+                var strGuid = guid.ToString("N", CultureInfo.InvariantCulture);
+                availablePackages = availablePackages.Where(x => x.guid.Equals(strGuid, StringComparison.OrdinalIgnoreCase));
             }
             }
 
 
-            return returnList;
+            return availablePackages;
         }
         }
 
 
-        /// <summary>
-        /// Determines whether [is package version up to date] [the specified package version info].
-        /// </summary>
-        /// <param name="packageVersionInfo">The package version info.</param>
-        /// <param name="currentServerVersion">The current server version.</param>
-        /// <returns><c>true</c> if [is package version up to date] [the specified package version info]; otherwise, <c>false</c>.</returns>
-        private static bool IsPackageVersionUpToDate(PackageVersionInfo packageVersionInfo, Version currentServerVersion)
+        /// <inheridoc />
+        public IEnumerable<PackageVersionInfo> GetCompatibleVersions(
+            IEnumerable<PackageVersionInfo> availableVersions,
+            Version minVersion = null,
+            PackageVersionClass classification = PackageVersionClass.Release)
         {
         {
-            if (string.IsNullOrEmpty(packageVersionInfo.requiredVersionStr))
+            var appVer = _applicationHost.ApplicationVersion;
+            availableVersions = availableVersions.Where(x => Version.Parse(x.requiredVersionStr) <= appVer);
+
+            if (minVersion != null)
             {
             {
-                return true;
+                availableVersions = availableVersions.Where(x => x.Version >= minVersion);
             }
             }
 
 
-            return Version.TryParse(packageVersionInfo.requiredVersionStr, out var requiredVersion) && currentServerVersion >= requiredVersion;
+            return availableVersions;
         }
         }
 
 
-        /// <summary>
-        /// Gets the package.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="guid">The assembly guid</param>
-        /// <param name="classification">The classification.</param>
-        /// <param name="version">The version.</param>
-        /// <returns>Task{PackageVersionInfo}.</returns>
-        public async Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version)
+        /// <inheritdoc />
+        public IEnumerable<PackageVersionInfo> GetCompatibleVersions(
+            IEnumerable<PackageInfo> availablePackages,
+            string name = null,
+            Guid guid = default,
+            Version minVersion = null,
+            PackageVersionClass classification = PackageVersionClass.Release)
         {
         {
-            var packages = await GetAvailablePackages(CancellationToken.None, false).ConfigureAwait(false);
-
-            var package = packages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase))
-                            ?? packages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase));
+            var package = FilterPackages(availablePackages, name, guid).FirstOrDefault();
 
 
+            // Package not found.
             if (package == null)
             if (package == null)
             {
             {
                 return null;
                 return null;
             }
             }
 
 
-            return package.versions.FirstOrDefault(v => v.Version == version && v.classification == classification);
-        }
-
-        /// <summary>
-        /// Gets the latest compatible version.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="guid">The assembly guid if this is a plug-in</param>
-        /// <param name="currentServerVersion">The current server version.</param>
-        /// <param name="classification">The classification.</param>
-        /// <returns>Task{PackageVersionInfo}.</returns>
-        public async Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release)
-        {
-            var packages = await GetAvailablePackages(CancellationToken.None, false).ConfigureAwait(false);
-
-            return GetLatestCompatibleVersion(packages, name, guid, currentServerVersion, classification);
-        }
-
-        /// <summary>
-        /// Gets the latest compatible version.
-        /// </summary>
-        /// <param name="availablePackages">The available packages.</param>
-        /// <param name="name">The name.</param>
-        /// <param name="currentServerVersion">The current server version.</param>
-        /// <param name="classification">The classification.</param>
-        /// <returns>PackageVersionInfo.</returns>
-        public PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release)
-        {
-            var package = availablePackages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase))
-                            ?? availablePackages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase));
-
-            return package?.versions
-                .OrderByDescending(x => x.Version)
-                .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, currentServerVersion));
+            return GetCompatibleVersions(
+                package.versions,
+                minVersion,
+                classification);
         }
         }
 
 
-        /// <summary>
-        /// Gets the available plugin updates.
-        /// </summary>
-        /// <param name="applicationVersion">The current server version.</param>
-        /// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns>
-        public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken)
+        /// <inheritdoc />
+        public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
         {
         {
-            var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
+            var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
 
 
             var systemUpdateLevel = _applicationHost.SystemUpdateLevel;
             var systemUpdateLevel = _applicationHost.SystemUpdateLevel;
 
 
             // Figure out what needs to be installed
             // Figure out what needs to be installed
-            return _applicationHost.Plugins.Select(p =>
+            return _applicationHost.Plugins.Select(x =>
             {
             {
-                var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel);
-
-                return latestPluginInfo != null && latestPluginInfo.Version > p.Version ? latestPluginInfo : null;
-            }).Where(i => i != null)
-            .Where(p => !string.IsNullOrEmpty(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
+                var compatibleversions = GetCompatibleVersions(catalog, x.Name, x.Id, x.Version, systemUpdateLevel);
+                return compatibleversions.FirstOrDefault(y => y.Version > x.Version);
+            }).Where(x => x != null)
+            .Where(x => !CompletedInstallations.Any(y => string.Equals(y.AssemblyGuid, x.guid, StringComparison.OrdinalIgnoreCase)));
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />
@@ -391,7 +284,7 @@ namespace Emby.Server.Implementations.Updates
             finally
             finally
             {
             {
                 // Dispose the progress object and remove the installation from the in-progress list
                 // Dispose the progress object and remove the installation from the in-progress list
-                tuple.Item2.Dispose();
+                tuple.innerCancellationTokenSource.Dispose();
             }
             }
         }
         }
 
 
@@ -537,18 +430,19 @@ namespace Emby.Server.Implementations.Updates
         {
         {
             lock (_currentInstallations)
             lock (_currentInstallations)
             {
             {
-                var install = _currentInstallations.Find(x => x.Item1.Id == id);
+                var install = _currentInstallations.Find(x => x.info.Id == id);
                 if (install == default((InstallationInfo, CancellationTokenSource)))
                 if (install == default((InstallationInfo, CancellationTokenSource)))
                 {
                 {
                     return false;
                     return false;
                 }
                 }
 
 
-                install.Item2.Cancel();
+                install.token.Cancel();
                 _currentInstallations.Remove(install);
                 _currentInstallations.Remove(install);
                 return true;
                 return true;
             }
             }
         }
         }
 
 
+        /// <inheritdoc />
         public void Dispose()
         public void Dispose()
         {
         {
             Dispose(true);
             Dispose(true);
@@ -567,7 +461,7 @@ namespace Emby.Server.Implementations.Updates
                 {
                 {
                     foreach (var tuple in _currentInstallations)
                     foreach (var tuple in _currentInstallations)
                     {
                     {
-                        tuple.Item2.Dispose();
+                        tuple.token.Dispose();
                     }
                     }
 
 
                     _currentInstallations.Clear();
                     _currentInstallations.Clear();

+ 15 - 12
MediaBrowser.Api/PackageService.cs

@@ -1,11 +1,11 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Common;
 using MediaBrowser.Common;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
@@ -139,7 +139,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetPackage request)
         public object Get(GetPackage request)
         {
         {
-            var packages = _installationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: typeof(PackageService).Assembly.GetName().Version).Result;
+            var packages = _installationManager.GetAvailablePackages().Result;
 
 
             var result = packages.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase))
             var result = packages.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase))
                          ?? packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
                          ?? packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
@@ -154,7 +154,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public async Task<object> Get(GetPackages request)
         public async Task<object> Get(GetPackages request)
         {
         {
-            IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, typeof(PackageService).Assembly.GetName().Version).ConfigureAwait(false);
+            IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
 
 
             if (!string.IsNullOrEmpty(request.TargetSystems))
             if (!string.IsNullOrEmpty(request.TargetSystems))
             {
             {
@@ -163,11 +163,6 @@ namespace MediaBrowser.Api
                 packages = packages.Where(p => apps.Contains(p.targetSystem));
                 packages = packages.Where(p => apps.Contains(p.targetSystem));
             }
             }
 
 
-            if (request.IsPremium.HasValue)
-            {
-                packages = packages.Where(p => p.isPremium == request.IsPremium.Value);
-            }
-
             if (request.IsAdult.HasValue)
             if (request.IsAdult.HasValue)
             {
             {
                 packages = packages.Where(p => p.adult == request.IsAdult.Value);
                 packages = packages.Where(p => p.adult == request.IsAdult.Value);
@@ -188,13 +183,21 @@ namespace MediaBrowser.Api
         /// <exception cref="ResourceNotFoundException"></exception>
         /// <exception cref="ResourceNotFoundException"></exception>
         public async Task Post(InstallPackage request)
         public async Task Post(InstallPackage request)
         {
         {
-            var package = string.IsNullOrEmpty(request.Version) ?
-                await _installationManager.GetLatestCompatibleVersion(request.Name, request.AssemblyGuid, typeof(PackageService).Assembly.GetName().Version, request.UpdateClass).ConfigureAwait(false) :
-                await _installationManager.GetPackage(request.Name, request.AssemblyGuid, request.UpdateClass, Version.Parse(request.Version)).ConfigureAwait(false);
+            var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
+            var package = _installationManager.GetCompatibleVersions(
+                    packages,
+                    request.Name,
+                    new Guid(request.AssemblyGuid),
+                    string.IsNullOrEmpty(request.Version) ? null : Version.Parse(request.Version),
+                    request.UpdateClass).FirstOrDefault();
 
 
             if (package == null)
             if (package == null)
             {
             {
-                throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
+                throw new ResourceNotFoundException(
+                    string.Format(
+                        CultureInfo.InvariantCulture,
+                        "Package not found: {0}",
+                        request.Name));
             }
             }
 
 
             await _installationManager.InstallPackage(package);
             await _installationManager.InstallPackage(package);

+ 1 - 1
MediaBrowser.Api/Session/SessionsService.cs

@@ -321,7 +321,7 @@ namespace MediaBrowser.Api.Session
                 DateCreated = DateTime.UtcNow,
                 DateCreated = DateTime.UtcNow,
                 DeviceId = _appHost.SystemId,
                 DeviceId = _appHost.SystemId,
                 DeviceName = _appHost.FriendlyName,
                 DeviceName = _appHost.FriendlyName,
-                AppVersion = _appHost.ApplicationVersion
+                AppVersion = _appHost.ApplicationVersionString
             });
             });
         }
         }
 
 

+ 5 - 12
MediaBrowser.Common/Cryptography/PasswordHash.cs

@@ -97,19 +97,12 @@ namespace MediaBrowser.Common.Cryptography
                 }
                 }
             }
             }
 
 
-            byte[] hash;
-            byte[] salt;
             // Check if the string also contains a salt
             // Check if the string also contains a salt
-            if (splitted.Length - index == 2)
-            {
-                salt = FromHexString(splitted[index++]);
-                hash = FromHexString(splitted[index++]);
-            }
-            else
-            {
-                salt = Array.Empty<byte>();
-                hash = FromHexString(splitted[index++]);
-            }
+            byte[] salt = splitted.Length - index == 2
+                ? FromHexString(splitted[index++])
+                : Array.Empty<byte>();
+
+            byte[] hash = FromHexString(splitted[index]);
 
 
             return new PasswordHash(id, hash, salt, parameters);
             return new PasswordHash(id, hash, salt, parameters);
         }
         }

+ 7 - 1
MediaBrowser.Common/IApplicationHost.cs

@@ -67,7 +67,13 @@ namespace MediaBrowser.Common
         /// Gets the application version.
         /// Gets the application version.
         /// </summary>
         /// </summary>
         /// <value>The application version.</value>
         /// <value>The application version.</value>
-        string ApplicationVersion { get; }
+        Version ApplicationVersion { get; }
+
+        /// <summary>
+        /// Gets the application version.
+        /// </summary>
+        /// <value>The application version.</value>
+        string ApplicationVersionString { get; }
 
 
         /// <summary>
         /// <summary>
         /// Gets the application user agent.
         /// Gets the application user agent.

+ 36 - 40
MediaBrowser.Common/Updates/IInstallationManager.cs

@@ -17,11 +17,6 @@ namespace MediaBrowser.Common.Updates
         event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
         event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
         event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
         event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
 
 
-        /// <summary>
-        /// The completed installations
-        /// </summary>
-        IEnumerable<InstallationInfo> CompletedInstallations { get; }
-
         /// <summary>
         /// <summary>
         /// Occurs when [plugin uninstalled].
         /// Occurs when [plugin uninstalled].
         /// </summary>
         /// </summary>
@@ -38,62 +33,63 @@ namespace MediaBrowser.Common.Updates
         event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
         event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
 
 
         /// <summary>
         /// <summary>
-        /// Gets all available packages.
+        /// The completed installations
         /// </summary>
         /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="withRegistration">if set to <c>true</c> [with registration].</param>
-        /// <param name="packageType">Type of the package.</param>
-        /// <param name="applicationVersion">The application version.</param>
-        /// <returns>Task{List{PackageInfo}}.</returns>
-        Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
-            bool withRegistration = true, string packageType = null, Version applicationVersion = null);
+        IEnumerable<InstallationInfo> CompletedInstallations { get; }
 
 
         /// <summary>
         /// <summary>
-        /// Gets all available packages from a static resource.
+        /// Gets all available packages.
         /// </summary>
         /// </summary>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{List{PackageInfo}}.</returns>
-        Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken);
+        /// <returns>Task{IReadOnlyList{PackageInfo}}.</returns>
+        Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default);
 
 
         /// <summary>
         /// <summary>
-        /// Gets the package.
+        /// Returns all plugins matching the requirements.
         /// </summary>
         /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="guid">The assembly guid</param>
-        /// <param name="classification">The classification.</param>
-        /// <param name="version">The version.</param>
-        /// <returns>Task{PackageVersionInfo}.</returns>
-        Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version);
+        /// <param name="availablePackages">The available packages.</param>
+        /// <param name="name">The name of the plugin.</param>
+        /// <param name="guid">The id of the plugin.</param>
+        /// <returns>All plugins matching the requirements.</returns>
+        IEnumerable<PackageInfo> FilterPackages(
+            IEnumerable<PackageInfo> availablePackages,
+            string name = null,
+            Guid guid = default);
 
 
         /// <summary>
         /// <summary>
-        /// Gets the latest compatible version.
+        /// Returns all compatible versions ordered from newest to oldest.
         /// </summary>
         /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="guid">The assembly guid</param>
-        /// <param name="currentServerVersion">The current server version.</param>
-        /// <param name="classification">The classification.</param>
-        /// <returns>Task{PackageVersionInfo}.</returns>
-        Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release);
+        /// <param name="availableVersions">The available version of the plugin.</param>
+        /// <param name="minVersion">The minimum required version of the plugin.</param>
+        /// <param name="classification">The classification of updates.</param>
+        /// <returns>All compatible versions ordered from newest to oldest.</returns>
+        IEnumerable<PackageVersionInfo> GetCompatibleVersions(
+            IEnumerable<PackageVersionInfo> availableVersions,
+            Version minVersion = null,
+            PackageVersionClass classification = PackageVersionClass.Release);
 
 
         /// <summary>
         /// <summary>
-        /// Gets the latest compatible version.
+        /// Returns all compatible versions ordered from newest to oldest.
         /// </summary>
         /// </summary>
         /// <param name="availablePackages">The available packages.</param>
         /// <param name="availablePackages">The available packages.</param>
         /// <param name="name">The name.</param>
         /// <param name="name">The name.</param>
-        /// <param name="guid">The assembly guid</param>
-        /// <param name="currentServerVersion">The current server version.</param>
+        /// <param name="guid">The guid of the plugin.</param>
+        /// <param name="minVersion">The minimum required version of the plugin.</param>
         /// <param name="classification">The classification.</param>
         /// <param name="classification">The classification.</param>
-        /// <returns>PackageVersionInfo.</returns>
-        PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release);
+        /// <returns>All compatible versions ordered from newest to oldest.</returns>
+        IEnumerable<PackageVersionInfo> GetCompatibleVersions(
+            IEnumerable<PackageInfo> availablePackages,
+            string name = null,
+            Guid guid = default,
+            Version minVersion = null,
+            PackageVersionClass classification = PackageVersionClass.Release);
 
 
         /// <summary>
         /// <summary>
-        /// Gets the available plugin updates.
+        /// Returns the available plugin updates.
         /// </summary>
         /// </summary>
-        /// <param name="applicationVersion">The current server version.</param>
-        /// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns>
-        Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken);
+        /// <returns>Tthe available plugin updates.</returns>
+        Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default);
 
 
         /// <summary>
         /// <summary>
         /// Installs the package.
         /// Installs the package.

+ 2 - 1
MediaBrowser.Model/Updates/PackageInfo.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.Collections.Generic;
 
 
 namespace MediaBrowser.Model.Updates
 namespace MediaBrowser.Model.Updates
 {
 {
@@ -150,7 +151,7 @@ namespace MediaBrowser.Model.Updates
         /// Gets or sets the versions.
         /// Gets or sets the versions.
         /// </summary>
         /// </summary>
         /// <value>The versions.</value>
         /// <value>The versions.</value>
-        public PackageVersionInfo[] versions { get; set; }
+        public IReadOnlyList<PackageVersionInfo> versions { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [enable in application store].
         /// Gets or sets a value indicating whether [enable in application store].

+ 0 - 1
MediaBrowser.Providers/TV/TheTVDB/TvdbUtils.cs

@@ -1,5 +1,4 @@
 using System;
 using System;
-using System.ComponentModel;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 namespace MediaBrowser.Providers.TV.TheTVDB
 namespace MediaBrowser.Providers.TV.TheTVDB
 {
 {

+ 4 - 4
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -205,7 +205,7 @@ namespace MediaBrowser.WebDashboard.Api
                     return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => Task.FromResult(stream));
                     return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => Task.FromResult(stream));
                 }
                 }
 
 
-                return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator(DashboardUIPath).ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersion, null));
+                return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator(DashboardUIPath).ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersionString, null));
             }
             }
 
 
             throw new ResourceNotFoundException();
             throw new ResourceNotFoundException();
@@ -342,7 +342,7 @@ namespace MediaBrowser.WebDashboard.Api
                 cacheDuration = TimeSpan.FromDays(365);
                 cacheDuration = TimeSpan.FromDays(365);
             }
             }
 
 
-            var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5();
+            var cacheKey = (_appHost.ApplicationVersionString + (localizationCulture ?? string.Empty) + path).GetMD5();
 
 
             // html gets modified on the fly
             // html gets modified on the fly
             if (contentType.StartsWith("text/html", StringComparison.OrdinalIgnoreCase))
             if (contentType.StartsWith("text/html", StringComparison.OrdinalIgnoreCase))
@@ -364,7 +364,7 @@ namespace MediaBrowser.WebDashboard.Api
         private Task<Stream> GetResourceStream(string basePath, string virtualPath, string localizationCulture)
         private Task<Stream> GetResourceStream(string basePath, string virtualPath, string localizationCulture)
         {
         {
             return GetPackageCreator(basePath)
             return GetPackageCreator(basePath)
-                .GetResource(virtualPath, null, localizationCulture, _appHost.ApplicationVersion);
+                .GetResource(virtualPath, null, localizationCulture, _appHost.ApplicationVersionString);
         }
         }
 
 
         private PackageCreator GetPackageCreator(string basePath)
         private PackageCreator GetPackageCreator(string basePath)
@@ -400,7 +400,7 @@ namespace MediaBrowser.WebDashboard.Api
                 CopyDirectory(inputPath, targetPath);
                 CopyDirectory(inputPath, targetPath);
             }
             }
 
 
-            var appVersion = _appHost.ApplicationVersion;
+            var appVersion = _appHost.ApplicationVersionString;
 
 
             await DumpHtml(packageCreator, inputPath, targetPath, mode, appVersion);
             await DumpHtml(packageCreator, inputPath, targetPath, mode, appVersion);