From 18855a7884ee5f33b124347425886cc974b424e8 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 13:34:09 +0000 Subject: [PATCH 1/5] Initialial upload --- .../Plugins/PluginManifest.cs | 5 + .../Updates/InstallationManager.cs | 98 ++++++++++++++++--- Jellyfin.Api/Controllers/PackageController.cs | 2 +- .../Routines/ReaddDefaultPluginRepository.cs | 6 +- .../Updates/IInstallationManager.cs | 7 +- MediaBrowser.Model/Updates/PackageInfo.cs | 12 +-- MediaBrowser.Model/Updates/RepositoryInfo.cs | 6 ++ MediaBrowser.Model/Updates/VersionInfo.cs | 30 +++++- 8 files changed, 134 insertions(+), 32 deletions(-) diff --git a/Emby.Server.Implementations/Plugins/PluginManifest.cs b/Emby.Server.Implementations/Plugins/PluginManifest.cs index 33762791bc..63cad82716 100644 --- a/Emby.Server.Implementations/Plugins/PluginManifest.cs +++ b/Emby.Server.Implementations/Plugins/PluginManifest.cs @@ -56,5 +56,10 @@ namespace Emby.Server.Implementations.Plugins /// Gets or sets the Version number of the plugin. /// public string Version { get; set; } + + /// + /// Gets or sets the Repository where the plugin originated. + /// + public string Repository { get; set; } } } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 851e7bd68b..e23e0790b9 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -93,17 +93,29 @@ namespace Emby.Server.Implementations.Updates public IEnumerable CompletedInstallations => _completedInstallationsInternal; /// - public async Task> GetPackages(string manifest, CancellationToken cancellationToken = default) + public async Task> GetPackages(string manifestName, string manifest, CancellationToken cancellationToken = default) { try { using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(manifest, cancellationToken).ConfigureAwait(false); + .GetAsync(new Uri(manifest), cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); try { - return await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); + var package = await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); + + // Store the repository and repository url with each version, as they may be spread apart. + foreach (var entry in package) + { + foreach (var ver in entry.versions) + { + ver.repositoryName = manifestName; + ver.repositoryUrl = manifest; + } + } + + return package; } catch (SerializationException ex) { @@ -123,17 +135,69 @@ namespace Emby.Server.Implementations.Updates } } + private static void MergeSort(IList source, IList dest) + { + int sLength = source.Count - 1; + int dLength = dest.Count; + int s = 0, d = 0; + var sourceVersion = source[0].VersionNumber; + var destVersion = dest[0].VersionNumber; + + while (d < dLength) + { + if (sourceVersion.CompareTo(destVersion) >= 0) + { + if (s < sLength) + { + sourceVersion = source[++s].VersionNumber; + } + else + { + // Append all of destination to the end of source. + while (d < dLength) + { + source.Add(dest[d++]); + } + + break; + } + } + else + { + source.Insert(s++, dest[d++]); + if (d >= dLength) + { + break; + } + + sLength++; + destVersion = dest[d].VersionNumber; + } + } + } + /// public async Task> GetAvailablePackages(CancellationToken cancellationToken = default) { var result = new List(); foreach (RepositoryInfo repository in _config.Configuration.PluginRepositories) { - foreach (var package in await GetPackages(repository.Url, cancellationToken).ConfigureAwait(true)) + if (repository.Enabled) { - package.repositoryName = repository.Name; - package.repositoryUrl = repository.Url; - result.Add(package); + // Where repositories have the same content, the details of the first is taken. + foreach (var package in await GetPackages(repository.Name, repository.Url, cancellationToken).ConfigureAwait(true)) + { + var existing = FilterPackages(result, package.name, Guid.Parse(package.guid)).FirstOrDefault(); + if (existing != null) + { + // Assumption is both lists are ordered, so slot these into the correct place. + MergeSort(existing.versions, package.versions); + } + else + { + result.Add(package); + } + } } } @@ -144,7 +208,8 @@ namespace Emby.Server.Implementations.Updates public IEnumerable FilterPackages( IEnumerable availablePackages, string name = null, - Guid guid = default) + Guid guid = default, + Version specificVersion = null) { if (name != null) { @@ -156,6 +221,11 @@ namespace Emby.Server.Implementations.Updates availablePackages = availablePackages.Where(x => Guid.Parse(x.guid) == guid); } + if (specificVersion != null) + { + availablePackages = availablePackages.Where(x => x.versions.Where(y => y.VersionNumber.Equals(specificVersion)).Any()); + } + return availablePackages; } @@ -167,7 +237,7 @@ namespace Emby.Server.Implementations.Updates Version minVersion = null, Version specificVersion = null) { - var package = FilterPackages(availablePackages, name, guid).FirstOrDefault(); + var package = FilterPackages(availablePackages, name, guid, specificVersion).FirstOrDefault(); // Package not found in repository if (package == null) @@ -181,21 +251,21 @@ namespace Emby.Server.Implementations.Updates if (specificVersion != null) { - availableVersions = availableVersions.Where(x => new Version(x.version) == specificVersion); + availableVersions = availableVersions.Where(x => x.VersionNumber.Equals(specificVersion)); } else if (minVersion != null) { - availableVersions = availableVersions.Where(x => new Version(x.version) >= minVersion); + availableVersions = availableVersions.Where(x => x.VersionNumber >= minVersion); } - foreach (var v in availableVersions.OrderByDescending(x => x.version)) + foreach (var v in availableVersions.OrderByDescending(x => x.VersionNumber)) { yield return new InstallationInfo { Changelog = v.changelog, Guid = new Guid(package.guid), Name = package.name, - Version = new Version(v.version), + Version = v.VersionNumber, SourceUrl = v.sourceUrl, Checksum = v.checksum }; @@ -322,7 +392,7 @@ namespace Emby.Server.Implementations.Updates private async Task PerformPackageInstallation(InstallationInfo package, CancellationToken cancellationToken) { - var extension = Path.GetExtension(package.SourceUrl); + var extension = Path.GetExtension(package.SourceUrl.ToString()); if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase)) { _logger.LogError("Only zip packages are supported. {SourceUrl} is not a zip archive.", package.SourceUrl); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 1f797d6bc3..83b3597665 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -99,7 +99,7 @@ namespace Jellyfin.Api.Controllers var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); if (!string.IsNullOrEmpty(repositoryUrl)) { - packages = packages.Where(p => p.repositoryUrl.Equals(repositoryUrl, StringComparison.OrdinalIgnoreCase)) + packages = packages.Where(p => p.versions.Where(q => q.repositoryUrl.Equals(repositoryUrl, StringComparison.OrdinalIgnoreCase)).Any()) .ToList(); } diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs index b281b5cc09..db605c54ec 100644 --- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Updates; @@ -14,7 +14,7 @@ namespace Jellyfin.Server.Migrations.Routines private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo { Name = "Jellyfin Stable", - Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" + Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json", }; /// @@ -46,4 +46,4 @@ namespace Jellyfin.Server.Migrations.Routines } } } -} \ No newline at end of file +} diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs index 6aa16fea74..585b1ee19e 100644 --- a/MediaBrowser.Common/Updates/IInstallationManager.cs +++ b/MediaBrowser.Common/Updates/IInstallationManager.cs @@ -19,10 +19,11 @@ namespace MediaBrowser.Common.Updates /// /// Parses a plugin manifest at the supplied URL. /// + /// Name of the repository. /// The URL to query. /// The cancellation token. /// Task{IReadOnlyList{PackageInfo}}. - Task> GetPackages(string manifest, CancellationToken cancellationToken = default); + Task> GetPackages(string manifestName, string manifest, CancellationToken cancellationToken = default); /// /// Gets all available packages. @@ -37,11 +38,13 @@ namespace MediaBrowser.Common.Updates /// The available packages. /// The name of the plugin. /// The id of the plugin. + /// The version of the plugin. /// All plugins matching the requirements. IEnumerable FilterPackages( IEnumerable availablePackages, string name = null, - Guid guid = default); + Guid guid = default, + Version specificVersion = null); /// /// Returns all compatible versions ordered from newest to oldest. diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs index 98b151d551..5e93043639 100644 --- a/MediaBrowser.Model/Updates/PackageInfo.cs +++ b/MediaBrowser.Model/Updates/PackageInfo.cs @@ -50,17 +50,7 @@ namespace MediaBrowser.Model.Updates /// Gets or sets the versions. /// /// The versions. - public IReadOnlyList versions { get; set; } - - /// - /// Gets or sets the repository name. - /// - public string repositoryName { get; set; } - - /// - /// Gets or sets the repository url. - /// - public string repositoryUrl { get; set; } + public IList versions { get; set; } /// /// Initializes a new instance of the class. diff --git a/MediaBrowser.Model/Updates/RepositoryInfo.cs b/MediaBrowser.Model/Updates/RepositoryInfo.cs index bd42e77f0f..705d3b33cc 100644 --- a/MediaBrowser.Model/Updates/RepositoryInfo.cs +++ b/MediaBrowser.Model/Updates/RepositoryInfo.cs @@ -16,5 +16,11 @@ namespace MediaBrowser.Model.Updates /// /// The URL. public string? Url { get; set; } + + /// + /// Gets or sets a value indicating whether the repository is enabled. + /// + /// true if enabled. + public bool Enabled { get; set; } = true; } } diff --git a/MediaBrowser.Model/Updates/VersionInfo.cs b/MediaBrowser.Model/Updates/VersionInfo.cs index a4aa0e75f3..844170999a 100644 --- a/MediaBrowser.Model/Updates/VersionInfo.cs +++ b/MediaBrowser.Model/Updates/VersionInfo.cs @@ -9,11 +9,29 @@ namespace MediaBrowser.Model.Updates /// public class VersionInfo { + private Version _version; + /// /// Gets or sets the version. /// /// The version. - public string version { get; set; } + public string version + { + get + { + return _version == null ? string.Empty : _version.ToString(); + } + + set + { + _version = Version.Parse(value); + } + } + + /// + /// Gets the version as a . + /// + public Version VersionNumber => _version; /// /// Gets or sets the changelog for this version. @@ -44,5 +62,15 @@ namespace MediaBrowser.Model.Updates /// /// The timestamp. public string timestamp { get; set; } + + /// + /// Gets or sets the repository name. + /// + public string repositoryName { get; set; } + + /// + /// Gets or sets the repository url. + /// + public string repositoryUrl { get; set; } } } From 1df58fbaa0b002a75c3b0d9f21b51461a2d9cd69 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 14:12:33 +0000 Subject: [PATCH 2/5] updated --- Emby.Server.Implementations/Updates/InstallationManager.cs | 4 ++-- Jellyfin.Api/Controllers/PluginsController.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index e23e0790b9..7a071c071a 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -392,7 +392,7 @@ namespace Emby.Server.Implementations.Updates private async Task PerformPackageInstallation(InstallationInfo package, CancellationToken cancellationToken) { - var extension = Path.GetExtension(package.SourceUrl.ToString()); + var extension = Path.GetExtension(package.SourceUrl); if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase)) { _logger.LogError("Only zip packages are supported. {SourceUrl} is not a zip archive.", package.SourceUrl); @@ -403,7 +403,7 @@ namespace Emby.Server.Implementations.Updates string targetDir = Path.Combine(_appPaths.PluginsPath, package.Name); using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(package.SourceUrl, cancellationToken).ConfigureAwait(false); + .GetAsync(new Uri(package.SourceUrl), cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // CA5351: Do Not Use Broken Cryptographic Algorithms diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 0f8ceba291..98f1bc2d23 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; From 31980e6f87543314d041d9ef4cc38356f752fb70 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 14:40:06 +0000 Subject: [PATCH 3/5] Fixed issue with plugins being deleted. --- Emby.Server.Implementations/ApplicationHost.cs | 5 +++-- Emby.Server.Implementations/Plugins/PluginManifest.cs | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 17b99c858f..cba9afb986 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -999,7 +999,7 @@ namespace Emby.Server.Implementations var versions = new List(); if (!Directory.Exists(path)) { - // Plugin path doesn't exist, don't try to enumerate subfolders. + // Plugin path doesn't exist, don't try to enumerate sub-folders. return Enumerable.Empty(); } @@ -1070,7 +1070,6 @@ namespace Emby.Server.Implementations if (!string.IsNullOrEmpty(lastName) && cleanup) { // Attempt a cleanup of old folders. - versions.RemoveAt(x); try { Logger.LogDebug("Deleting {Path}", versions[x].Path); @@ -1080,6 +1079,8 @@ namespace Emby.Server.Implementations { Logger.LogWarning(e, "Unable to delete {Path}", versions[x].Path); } + + versions.RemoveAt(x); } } diff --git a/Emby.Server.Implementations/Plugins/PluginManifest.cs b/Emby.Server.Implementations/Plugins/PluginManifest.cs index 63cad82716..33762791bc 100644 --- a/Emby.Server.Implementations/Plugins/PluginManifest.cs +++ b/Emby.Server.Implementations/Plugins/PluginManifest.cs @@ -56,10 +56,5 @@ namespace Emby.Server.Implementations.Plugins /// Gets or sets the Version number of the plugin. /// public string Version { get; set; } - - /// - /// Gets or sets the Repository where the plugin originated. - /// - public string Repository { get; set; } } } From 452ca4565ff245a3dec670fbe5b9881df76d9434 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 15:39:00 +0000 Subject: [PATCH 4/5] reversing other PR --- Emby.Server.Implementations/ApplicationHost.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index cba9afb986..17b99c858f 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -999,7 +999,7 @@ namespace Emby.Server.Implementations var versions = new List(); if (!Directory.Exists(path)) { - // Plugin path doesn't exist, don't try to enumerate sub-folders. + // Plugin path doesn't exist, don't try to enumerate subfolders. return Enumerable.Empty(); } @@ -1070,6 +1070,7 @@ namespace Emby.Server.Implementations if (!string.IsNullOrEmpty(lastName) && cleanup) { // Attempt a cleanup of old folders. + versions.RemoveAt(x); try { Logger.LogDebug("Deleting {Path}", versions[x].Path); @@ -1079,8 +1080,6 @@ namespace Emby.Server.Implementations { Logger.LogWarning(e, "Unable to delete {Path}", versions[x].Path); } - - versions.RemoveAt(x); } } From 14fc7e6408aa35c7a87470f3cd2fc87971f7c442 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 15:40:20 +0000 Subject: [PATCH 5/5] revert changes. --- .../Migrations/Routines/ReaddDefaultPluginRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs index db605c54ec..394f14d63c 100644 --- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -14,7 +14,7 @@ namespace Jellyfin.Server.Migrations.Routines private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo { Name = "Jellyfin Stable", - Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json", + Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" }; ///