mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-03 13:44:22 -04:00
Delete plugin working.
This commit is contained in:
parent
7986465cf7
commit
a246a77ada
@ -78,8 +78,27 @@ namespace Emby.Server.Implementations
|
|||||||
/// <returns>An IEnumerable{Assembly}.</returns>
|
/// <returns>An IEnumerable{Assembly}.</returns>
|
||||||
public IEnumerable<Assembly> LoadAssemblies()
|
public IEnumerable<Assembly> LoadAssemblies()
|
||||||
{
|
{
|
||||||
|
// Attempt to remove any deleted plugins and change any successors to be active.
|
||||||
|
for (int a = _plugins.Count - 1; a >= 0; a--)
|
||||||
|
{
|
||||||
|
var plugin = _plugins[a];
|
||||||
|
if (plugin.Manifest.Status == PluginStatus.DeleteOnStartup && DeletePlugin(plugin))
|
||||||
|
{
|
||||||
|
UpdateSuccessors(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now load the assemblies..
|
||||||
foreach (var plugin in _plugins)
|
foreach (var plugin in _plugins)
|
||||||
{
|
{
|
||||||
|
CheckIfStillSuperceded(plugin);
|
||||||
|
|
||||||
|
if (plugin.IsEnabledAndSupported == false)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Skipping disabled plugin {Version} of {Name} ", plugin.Version, plugin.Name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var file in plugin.DllFiles)
|
foreach (var file in plugin.DllFiles)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -183,15 +202,13 @@ namespace Emby.Server.Implementations
|
|||||||
throw new ArgumentNullException(nameof(plugin));
|
throw new ArgumentNullException(nameof(plugin));
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.Instance?.OnUninstalling();
|
|
||||||
|
|
||||||
if (DeletePlugin(plugin))
|
if (DeletePlugin(plugin))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unable to delete, so disable.
|
// Unable to delete, so disable.
|
||||||
return ChangePluginState(plugin, PluginStatus.Disabled);
|
return ChangePluginState(plugin, PluginStatus.DeleteOnStartup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -205,11 +222,18 @@ namespace Emby.Server.Implementations
|
|||||||
{
|
{
|
||||||
if (version == null)
|
if (version == null)
|
||||||
{
|
{
|
||||||
// If no version is given, return the largest version number. (This is for backwards compatibility).
|
// If no version is given, return the current instance.
|
||||||
plugin = _plugins.Where(p => p.Id.Equals(id)).OrderByDescending(p => p.Version).FirstOrDefault();
|
var plugins = _plugins.Where(p => p.Id.Equals(id));
|
||||||
|
|
||||||
|
plugin = plugins.FirstOrDefault(p => p.Instance != null);
|
||||||
|
if (plugin == null)
|
||||||
|
{
|
||||||
|
plugin = plugins.OrderByDescending(p => p.Version).FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Match id and version number.
|
||||||
plugin = _plugins.FirstOrDefault(p => p.Id.Equals(id) && p.Version.Equals(version));
|
plugin = _plugins.FirstOrDefault(p => p.Id.Equals(id) && p.Version.Equals(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +288,6 @@ namespace Emby.Server.Implementations
|
|||||||
var predecessor = _plugins.OrderByDescending(p => p.Version)
|
var predecessor = _plugins.OrderByDescending(p => p.Version)
|
||||||
.FirstOrDefault(
|
.FirstOrDefault(
|
||||||
p => p.Id.Equals(plugin.Id)
|
p => p.Id.Equals(plugin.Id)
|
||||||
&& p.Name.Equals(plugin.Name, StringComparison.OrdinalIgnoreCase)
|
|
||||||
&& p.IsEnabledAndSupported
|
&& p.IsEnabledAndSupported
|
||||||
&& p.Version != plugin.Version);
|
&& p.Version != plugin.Version);
|
||||||
|
|
||||||
@ -381,17 +404,6 @@ namespace Emby.Server.Implementations
|
|||||||
// Find the record for this plugin.
|
// Find the record for this plugin.
|
||||||
var plugin = GetPluginByType(type);
|
var plugin = GetPluginByType(type);
|
||||||
|
|
||||||
if (plugin != null)
|
|
||||||
{
|
|
||||||
CheckIfStillSuperceded(plugin);
|
|
||||||
|
|
||||||
if (plugin.IsEnabledAndSupported == true)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Skipping disabled plugin {Version} of {Name} ", plugin.Version, plugin.Name);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Creating instance of {Type}", type);
|
_logger.LogDebug("Creating instance of {Type}", type);
|
||||||
@ -489,6 +501,7 @@ namespace Emby.Server.Implementations
|
|||||||
{
|
{
|
||||||
_logger.LogDebug("Deleting {Path}", plugin.Path);
|
_logger.LogDebug("Deleting {Path}", plugin.Path);
|
||||||
Directory.Delete(plugin.Path, true);
|
Directory.Delete(plugin.Path, true);
|
||||||
|
_plugins.Remove(plugin);
|
||||||
}
|
}
|
||||||
#pragma warning disable CA1031 // Do not catch general exception types
|
#pragma warning disable CA1031 // Do not catch general exception types
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -661,8 +674,8 @@ namespace Emby.Server.Implementations
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the manifest so its not loaded next time.
|
manifest.Status = PluginStatus.DeleteOnStartup;
|
||||||
manifest.Status = PluginStatus.Disabled;
|
|
||||||
SaveManifest(manifest, entry.Path);
|
SaveManifest(manifest, entry.Path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <returns>A <see cref="PackageInfo"/> containing package information.</returns>
|
/// <returns>A <see cref="PackageInfo"/> containing package information.</returns>
|
||||||
[HttpGet("Packages/{name}")]
|
[HttpGet("Packages/{name}")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[Produces(JsonDefaults.CamelCaseMediaType)]
|
|
||||||
public async Task<ActionResult<PackageInfo>> GetPackageInfo(
|
public async Task<ActionResult<PackageInfo>> GetPackageInfo(
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromQuery] Guid? assemblyGuid)
|
[FromQuery] Guid? assemblyGuid)
|
||||||
@ -73,7 +72,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <returns>An <see cref="PackageInfo"/> containing available packages information.</returns>
|
/// <returns>An <see cref="PackageInfo"/> containing available packages information.</returns>
|
||||||
[HttpGet("Packages")]
|
[HttpGet("Packages")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[Produces(JsonDefaults.CamelCaseMediaType)]
|
|
||||||
public async Task<IEnumerable<PackageInfo>> GetPackages()
|
public async Task<IEnumerable<PackageInfo>> GetPackages()
|
||||||
{
|
{
|
||||||
IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
|
IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
|
||||||
@ -148,7 +146,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <returns>An <see cref="OkResult"/> containing the list of package repositories.</returns>
|
/// <returns>An <see cref="OkResult"/> containing the list of package repositories.</returns>
|
||||||
[HttpGet("Repositories")]
|
[HttpGet("Repositories")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[Produces(JsonDefaults.CamelCaseMediaType)]
|
|
||||||
public ActionResult<IEnumerable<RepositoryInfo>> GetRepositories()
|
public ActionResult<IEnumerable<RepositoryInfo>> GetRepositories()
|
||||||
{
|
{
|
||||||
return _serverConfigurationManager.Configuration.PluginRepositories;
|
return _serverConfigurationManager.Configuration.PluginRepositories;
|
||||||
|
@ -14,7 +14,6 @@ using MediaBrowser.Common.Configuration;
|
|||||||
using MediaBrowser.Common.Json;
|
using MediaBrowser.Common.Json;
|
||||||
using MediaBrowser.Common.Plugins;
|
using MediaBrowser.Common.Plugins;
|
||||||
using MediaBrowser.Common.Updates;
|
using MediaBrowser.Common.Updates;
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
using MediaBrowser.Model.Plugins;
|
using MediaBrowser.Model.Plugins;
|
||||||
@ -130,7 +129,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <response code="204">Plugin enabled.</response>
|
/// <response code="204">Plugin enabled.</response>
|
||||||
/// <response code="404">Plugin not found.</response>
|
/// <response code="404">Plugin not found.</response>
|
||||||
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
||||||
[HttpPost("{pluginId}/Enable")]
|
[HttpPost("{pluginId}/{version}/Enable")]
|
||||||
[Authorize(Policy = Policies.RequiresElevation)]
|
[Authorize(Policy = Policies.RequiresElevation)]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
@ -153,7 +152,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <response code="204">Plugin disabled.</response>
|
/// <response code="204">Plugin disabled.</response>
|
||||||
/// <response code="404">Plugin not found.</response>
|
/// <response code="404">Plugin not found.</response>
|
||||||
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
||||||
[HttpPost("{pluginId}/Disable")]
|
[HttpPost("{pluginId}/{version}/Disable")]
|
||||||
[Authorize(Policy = Policies.RequiresElevation)]
|
[Authorize(Policy = Policies.RequiresElevation)]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
@ -176,11 +175,11 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <response code="204">Plugin uninstalled.</response>
|
/// <response code="204">Plugin uninstalled.</response>
|
||||||
/// <response code="404">Plugin not found.</response>
|
/// <response code="404">Plugin not found.</response>
|
||||||
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
||||||
[HttpDelete("{pluginId}")]
|
[HttpDelete("{pluginId}/{version}")]
|
||||||
[Authorize(Policy = Policies.RequiresElevation)]
|
[Authorize(Policy = Policies.RequiresElevation)]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId, Version version)
|
public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId, [FromRoute, Required] Version version)
|
||||||
{
|
{
|
||||||
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
||||||
{
|
{
|
||||||
@ -195,7 +194,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// Gets plugin configuration.
|
/// Gets plugin configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pluginId">Plugin id.</param>
|
/// <param name="pluginId">Plugin id.</param>
|
||||||
/// <param name="version">Plugin version.</param>
|
|
||||||
/// <response code="200">Plugin configuration returned.</response>
|
/// <response code="200">Plugin configuration returned.</response>
|
||||||
/// <response code="404">Plugin not found or plugin configuration not found.</response>
|
/// <response code="404">Plugin not found or plugin configuration not found.</response>
|
||||||
/// <returns>Plugin configuration.</returns>
|
/// <returns>Plugin configuration.</returns>
|
||||||
@ -203,9 +201,9 @@ namespace Jellyfin.Api.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesFile(MediaTypeNames.Application.Json)]
|
[ProducesFile(MediaTypeNames.Application.Json)]
|
||||||
public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute, Required] Guid pluginId, [FromRoute] Version? version)
|
public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute, Required] Guid pluginId)
|
||||||
{
|
{
|
||||||
if (_pluginManager.TryGetPlugin(pluginId, version, out var plugin)
|
if (_pluginManager.TryGetPlugin(pluginId, null, out var plugin)
|
||||||
&& plugin!.Instance is IHasPluginConfiguration configPlugin)
|
&& plugin!.Instance is IHasPluginConfiguration configPlugin)
|
||||||
{
|
{
|
||||||
return configPlugin.Configuration;
|
return configPlugin.Configuration;
|
||||||
@ -221,7 +219,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// Accepts plugin configuration as JSON body.
|
/// Accepts plugin configuration as JSON body.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="pluginId">Plugin id.</param>
|
/// <param name="pluginId">Plugin id.</param>
|
||||||
/// <param name="version">Plugin version.</param>
|
|
||||||
/// <response code="204">Plugin configuration updated.</response>
|
/// <response code="204">Plugin configuration updated.</response>
|
||||||
/// <response code="404">Plugin not found or plugin does not have configuration.</response>
|
/// <response code="404">Plugin not found or plugin does not have configuration.</response>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
@ -232,9 +229,9 @@ namespace Jellyfin.Api.Controllers
|
|||||||
[HttpPost("{pluginId}/Configuration")]
|
[HttpPost("{pluginId}/Configuration")]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> UpdatePluginConfiguration([FromRoute, Required] Guid pluginId, [FromRoute] Version? version)
|
public async Task<ActionResult> UpdatePluginConfiguration([FromRoute, Required] Guid pluginId)
|
||||||
{
|
{
|
||||||
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin)
|
if (!_pluginManager.TryGetPlugin(pluginId, null, out var plugin)
|
||||||
|| plugin?.Instance is not IHasPluginConfiguration configPlugin)
|
|| plugin?.Instance is not IHasPluginConfiguration configPlugin)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -258,12 +255,12 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <param name="version">Plugin version.</param>
|
/// <param name="version">Plugin version.</param>
|
||||||
/// <response code="200">Plugin image returned.</response>
|
/// <response code="200">Plugin image returned.</response>
|
||||||
/// <returns>Plugin's image.</returns>
|
/// <returns>Plugin's image.</returns>
|
||||||
[HttpGet("{pluginId}/Image")]
|
[HttpGet("{pluginId}/{version}/Image")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesImageFile]
|
[ProducesImageFile]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public ActionResult GetPluginImage([FromRoute, Required] Guid pluginId, [FromRoute] Version? version)
|
public ActionResult GetPluginImage([FromRoute, Required] Guid pluginId, [FromRoute, Required] Version version)
|
||||||
{
|
{
|
||||||
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
||||||
{
|
{
|
||||||
@ -292,12 +289,12 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <param name="version">Plugin version.</param>
|
/// <param name="version">Plugin version.</param>
|
||||||
/// <response code="200">Plugin image returned.</response>
|
/// <response code="200">Plugin image returned.</response>
|
||||||
/// <returns>Plugin's image.</returns>
|
/// <returns>Plugin's image.</returns>
|
||||||
[HttpGet("{pluginId}/StatusImage")]
|
[HttpGet("{pluginId}/{version}/StatusImage")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesImageFile]
|
[ProducesImageFile]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public ActionResult GetPluginStatusImage([FromRoute, Required] Guid pluginId, [FromRoute] Version? version)
|
public ActionResult GetPluginStatusImage([FromRoute, Required] Guid pluginId, [FromRoute, Required] Version version)
|
||||||
{
|
{
|
||||||
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
if (!_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
||||||
{
|
{
|
||||||
@ -316,7 +313,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// Gets a plugin's manifest.
|
/// Gets a plugin's manifest.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pluginId">Plugin id.</param>
|
/// <param name="pluginId">Plugin id.</param>
|
||||||
/// <param name="version">Plugin version.</param>
|
|
||||||
/// <response code="204">Plugin manifest returned.</response>
|
/// <response code="204">Plugin manifest returned.</response>
|
||||||
/// <response code="404">Plugin not found.</response>
|
/// <response code="404">Plugin not found.</response>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
@ -328,9 +324,9 @@ namespace Jellyfin.Api.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesFile(MediaTypeNames.Application.Json)]
|
[ProducesFile(MediaTypeNames.Application.Json)]
|
||||||
public ActionResult<PluginManifest> GetPluginManifest([FromRoute, Required] Guid pluginId, [FromRoute] Version? version)
|
public ActionResult<PluginManifest> GetPluginManifest([FromRoute, Required] Guid pluginId)
|
||||||
{
|
{
|
||||||
if (_pluginManager.TryGetPlugin(pluginId, version, out var plugin))
|
if (_pluginManager.TryGetPlugin(pluginId, null, out var plugin))
|
||||||
{
|
{
|
||||||
return Ok(plugin!.Manifest);
|
return Ok(plugin!.Manifest);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ namespace MediaBrowser.Model.Plugins
|
|||||||
Disabled = -1,
|
Disabled = -1,
|
||||||
NotSupported = -2,
|
NotSupported = -2,
|
||||||
Malfunction = -3,
|
Malfunction = -3,
|
||||||
Superceded = -4
|
Superceded = -4,
|
||||||
|
DeleteOnStartup = -5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user