mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	Merge pull request #3401 from BaronGreenback/Plugins
Fix for windows plug-in upgrades issue: #1623
This commit is contained in:
		
						commit
						bc5404cd6f
					
				@ -4,6 +4,7 @@ using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net;
 | 
			
		||||
@ -37,6 +38,7 @@ using Emby.Server.Implementations.LiveTv;
 | 
			
		||||
using Emby.Server.Implementations.Localization;
 | 
			
		||||
using Emby.Server.Implementations.Net;
 | 
			
		||||
using Emby.Server.Implementations.Playlists;
 | 
			
		||||
using Emby.Server.Implementations.Plugins;
 | 
			
		||||
using Emby.Server.Implementations.QuickConnect;
 | 
			
		||||
using Emby.Server.Implementations.ScheduledTasks;
 | 
			
		||||
using Emby.Server.Implementations.Security;
 | 
			
		||||
@ -119,6 +121,7 @@ namespace Emby.Server.Implementations
 | 
			
		||||
        private readonly IFileSystem _fileSystemManager;
 | 
			
		||||
        private readonly INetworkManager _networkManager;
 | 
			
		||||
        private readonly IXmlSerializer _xmlSerializer;
 | 
			
		||||
        private readonly IJsonSerializer _jsonSerializer;
 | 
			
		||||
        private readonly IStartupOptions _startupOptions;
 | 
			
		||||
 | 
			
		||||
        private IMediaEncoder _mediaEncoder;
 | 
			
		||||
@ -255,6 +258,8 @@ namespace Emby.Server.Implementations
 | 
			
		||||
            IServiceCollection serviceCollection)
 | 
			
		||||
        {
 | 
			
		||||
            _xmlSerializer = new MyXmlSerializer();
 | 
			
		||||
            _jsonSerializer = new JsonSerializer();            
 | 
			
		||||
            
 | 
			
		||||
            ServiceCollection = serviceCollection;
 | 
			
		||||
 | 
			
		||||
            _networkManager = networkManager;
 | 
			
		||||
@ -1021,6 +1026,108 @@ namespace Emby.Server.Implementations
 | 
			
		||||
 | 
			
		||||
        protected abstract void RestartInternal();
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Comparison function used in <see cref="GetPlugins" />.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="a">Item to compare.</param>
 | 
			
		||||
        /// <param name="b">Item to compare with.</param>
 | 
			
		||||
        /// <returns>Boolean result of the operation.</returns>
 | 
			
		||||
        private static int VersionCompare(
 | 
			
		||||
            (Version PluginVersion, string Name, string Path) a,
 | 
			
		||||
            (Version PluginVersion, string Name, string Path) b)
 | 
			
		||||
        {
 | 
			
		||||
            int compare = string.Compare(a.Name, b.Name, true, CultureInfo.InvariantCulture);
 | 
			
		||||
 | 
			
		||||
            if (compare == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return a.PluginVersion.CompareTo(b.PluginVersion);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return compare;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Returns a list of plugins to install.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="path">Path to check.</param>
 | 
			
		||||
        /// <param name="cleanup">True if an attempt should be made to delete old plugs.</param>
 | 
			
		||||
        /// <returns>Enumerable list of dlls to load.</returns>
 | 
			
		||||
        private IEnumerable<string> GetPlugins(string path, bool cleanup = true)
 | 
			
		||||
        {
 | 
			
		||||
            var dllList = new List<string>();
 | 
			
		||||
            var versions = new List<(Version PluginVersion, string Name, string Path)>();
 | 
			
		||||
            var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
 | 
			
		||||
            string metafile;
 | 
			
		||||
 | 
			
		||||
            foreach (var dir in directories)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    metafile = Path.Combine(dir, "meta.json");
 | 
			
		||||
                    if (File.Exists(metafile))
 | 
			
		||||
                    {
 | 
			
		||||
                        var manifest = _jsonSerializer.DeserializeFromFile<PluginManifest>(metafile);
 | 
			
		||||
 | 
			
		||||
                        if (!Version.TryParse(manifest.TargetAbi, out var targetAbi))
 | 
			
		||||
                        {
 | 
			
		||||
                            targetAbi = new Version(0, 0, 0, 1);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (!Version.TryParse(manifest.Version, out var version))
 | 
			
		||||
                        {
 | 
			
		||||
                            version = new Version(0, 0, 0, 1);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (ApplicationVersion >= targetAbi)
 | 
			
		||||
                        {
 | 
			
		||||
                            // Only load Plugins if the plugin is built for this version or below.
 | 
			
		||||
                            versions.Add((version, manifest.Name, dir));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        metafile = dir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries)[^1];
 | 
			
		||||
                        // Add it under the path name and version 0.0.0.1.
 | 
			
		||||
                        versions.Add((new Version(0, 0, 0, 1), metafile, dir));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            string lastName = string.Empty;
 | 
			
		||||
            versions.Sort(VersionCompare);
 | 
			
		||||
            // Traverse backwards through the list.
 | 
			
		||||
            // The first item will be the latest version.
 | 
			
		||||
            for (int x = versions.Count - 1; x >= 0; x--)
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.Equals(lastName, versions[x].Name, StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    dllList.AddRange(Directory.EnumerateFiles(versions[x].Path, "*.dll", SearchOption.AllDirectories));
 | 
			
		||||
                    lastName = versions[x].Name;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!string.IsNullOrEmpty(lastName) && cleanup)
 | 
			
		||||
                {
 | 
			
		||||
                    // Attempt a cleanup of old folders.
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        Logger.LogDebug("Deleting {Path}", versions[x].Path);
 | 
			
		||||
                        Directory.Delete(versions[x].Path, true);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception e)
 | 
			
		||||
                    {
 | 
			
		||||
                        Logger.LogWarning(e, "Unable to delete {Path}", versions[x].Path);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return dllList;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the composable part assemblies.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -1029,7 +1136,7 @@ namespace Emby.Server.Implementations
 | 
			
		||||
        {
 | 
			
		||||
            if (Directory.Exists(ApplicationPaths.PluginsPath))
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var file in Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories))
 | 
			
		||||
                foreach (var file in GetPlugins(ApplicationPaths.PluginsPath))
 | 
			
		||||
                {
 | 
			
		||||
                    Assembly plugAss;
 | 
			
		||||
                    try
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								Emby.Server.Implementations/Plugins/PluginManifest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								Emby.Server.Implementations/Plugins/PluginManifest.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Plugins
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Defines a Plugin manifest file.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class PluginManifest
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the category of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Category { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the changelog information.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Changelog { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the description of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Description { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the Global Unique Identifier for the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public Guid Guid { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the Name of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets an overview of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Overview { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the owner of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Owner { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the compatibility version for the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string TargetAbi { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the timestamp of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public DateTime Timestamp { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the Version number of the plugin.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public string Version { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -15,12 +15,14 @@ using MediaBrowser.Common.Configuration;
 | 
			
		||||
using MediaBrowser.Common.Net;
 | 
			
		||||
using MediaBrowser.Common.Plugins;
 | 
			
		||||
using MediaBrowser.Common.Updates;
 | 
			
		||||
using MediaBrowser.Common.System;
 | 
			
		||||
using MediaBrowser.Controller.Configuration;
 | 
			
		||||
using MediaBrowser.Model.IO;
 | 
			
		||||
using MediaBrowser.Model.Net;
 | 
			
		||||
using MediaBrowser.Model.Serialization;
 | 
			
		||||
using MediaBrowser.Model.Updates;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using MediaBrowser.Model.System;
 | 
			
		||||
 | 
			
		||||
namespace Emby.Server.Implementations.Updates
 | 
			
		||||
{
 | 
			
		||||
@ -377,11 +379,20 @@ namespace Emby.Server.Implementations.Updates
 | 
			
		||||
                throw new InvalidDataException("The checksum of the received data doesn't match.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Version folder as they cannot be overwritten in Windows.
 | 
			
		||||
            targetDir += "_" + package.Version;
 | 
			
		||||
 | 
			
		||||
            if (Directory.Exists(targetDir))
 | 
			
		||||
            {
 | 
			
		||||
                Directory.Delete(targetDir, true);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    Directory.Delete(targetDir, true);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    // Ignore any exceptions.
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            stream.Position = 0;
 | 
			
		||||
            _zipClient.ExtractAllFromZip(stream, targetDir, true);
 | 
			
		||||
 | 
			
		||||
@ -423,15 +434,22 @@ namespace Emby.Server.Implementations.Updates
 | 
			
		||||
                path = file;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (isDirectory)
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogInformation("Deleting plugin directory {0}", path);
 | 
			
		||||
                Directory.Delete(path, true);
 | 
			
		||||
                if (isDirectory)
 | 
			
		||||
                {
 | 
			
		||||
                    _logger.LogInformation("Deleting plugin directory {0}", path);
 | 
			
		||||
                    Directory.Delete(path, true);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    _logger.LogInformation("Deleting plugin file {0}", path);
 | 
			
		||||
                    _fileSystem.DeleteFile(path);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogInformation("Deleting plugin file {0}", path);
 | 
			
		||||
                _fileSystem.DeleteFile(path);
 | 
			
		||||
                // Ignore file errors.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var list = _config.Configuration.UninstalledPlugins.ToList();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user